OpenTTD
vehicle.cpp
Go to the documentation of this file.
1 /* $Id: vehicle.cpp 27148 2015-02-14 12:53:07Z 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 
1294 uint8 CalcPercentVehicleFilled(const Vehicle *front, StringID *colour)
1295 {
1296  int count = 0;
1297  int max = 0;
1298  int cars = 0;
1299  int unloading = 0;
1300  bool loading = false;
1301 
1302  bool is_loading = front->current_order.IsType(OT_LOADING);
1303 
1304  /* The station may be NULL when the (colour) string does not need to be set. */
1305  const Station *st = Station::GetIfValid(front->last_station_visited);
1306  assert(colour == NULL || (st != NULL && is_loading));
1307 
1308  bool order_no_load = is_loading && (front->current_order.GetLoadType() & OLFB_NO_LOAD);
1309  bool order_full_load = is_loading && (front->current_order.GetLoadType() & OLFB_FULL_LOAD);
1310 
1311  /* Count up max and used */
1312  for (const Vehicle *v = front; v != NULL; v = v->Next()) {
1313  count += v->cargo.StoredCount();
1314  max += v->cargo_cap;
1315  if (v->cargo_cap != 0 && colour != NULL) {
1316  unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0;
1317  loading |= !order_no_load &&
1318  (order_full_load || st->goods[v->cargo_type].HasRating()) &&
1320  cars++;
1321  }
1322  }
1323 
1324  if (colour != NULL) {
1325  if (unloading == 0 && loading) {
1326  *colour = STR_PERCENT_UP;
1327  } else if (unloading == 0 && !loading) {
1328  *colour = STR_PERCENT_NONE;
1329  } else if (cars == unloading || !loading) {
1330  *colour = STR_PERCENT_DOWN;
1331  } else {
1332  *colour = STR_PERCENT_UP_DOWN;
1333  }
1334  }
1335 
1336  /* Train without capacity */
1337  if (max == 0) return 100;
1338 
1339  /* Return the percentage */
1340  return (count * 100) / max;
1341 }
1342 
1348 {
1349  /* Always work with the front of the vehicle */
1350  assert(v == v->First());
1351 
1352  switch (v->type) {
1353  case VEH_TRAIN: {
1354  Train *t = Train::From(v);
1356  /* Clear path reservation */
1357  SetDepotReservation(t->tile, false);
1359 
1361  t->wait_counter = 0;
1362  t->force_proceed = TFP_NONE;
1363  ClrBit(t->flags, VRF_TOGGLE_REVERSE);
1365  break;
1366  }
1367 
1368  case VEH_ROAD:
1370  break;
1371 
1372  case VEH_SHIP: {
1374  Ship *ship = Ship::From(v);
1375  ship->state = TRACK_BIT_DEPOT;
1376  ship->UpdateCache();
1377  ship->UpdateViewport(true, true);
1379  break;
1380  }
1381 
1382  case VEH_AIRCRAFT:
1385  break;
1386  default: NOT_REACHED();
1387  }
1389 
1390  if (v->type != VEH_TRAIN) {
1391  /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
1392  * 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 */
1394  }
1396 
1397  v->vehstatus |= VS_HIDDEN;
1398  v->cur_speed = 0;
1399 
1401 
1402  /* After a vehicle trigger, the graphics and properties of the vehicle could change. */
1403  TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
1404  v->MarkDirty();
1405 
1406  if (v->current_order.IsType(OT_GOTO_DEPOT)) {
1408 
1409  const Order *real_order = v->GetOrder(v->cur_real_order_index);
1410 
1411  /* Test whether we are heading for this depot. If not, do nothing.
1412  * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
1414  real_order != NULL && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) &&
1415  (v->type == VEH_AIRCRAFT ? v->current_order.GetDestination() != GetStationIndex(v->tile) : v->dest_tile != v->tile)) {
1416  /* We are heading for another depot, keep driving. */
1417  return;
1418  }
1419 
1420  if (v->current_order.IsRefit()) {
1421  Backup<CompanyByte> cur_company(_current_company, v->owner, FILE_LINE);
1422  CommandCost cost = DoCommand(v->tile, v->index, v->current_order.GetRefitCargo() | 0xFF << 8, DC_EXEC, GetCmdRefitVeh(v));
1423  cur_company.Restore();
1424 
1425  if (cost.Failed()) {
1426  _vehicles_to_autoreplace[v] = false;
1427  if (v->owner == _local_company) {
1428  /* Notify the user that we stopped the vehicle */
1429  SetDParam(0, v->index);
1430  AddVehicleAdviceNewsItem(STR_NEWS_ORDER_REFIT_FAILED, v->index);
1431  }
1432  } else if (cost.GetCost() != 0) {
1433  v->profit_this_year -= cost.GetCost() << 8;
1434  if (v->owner == _local_company) {
1435  ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
1436  }
1437  }
1438  }
1439 
1441  /* Part of orders */
1443  UpdateVehicleTimetable(v, true);
1445  }
1447  /* Vehicles are always stopped on entering depots. Do not restart this one. */
1448  _vehicles_to_autoreplace[v] = false;
1449  /* Invalidate last_loading_station. As the link from the station
1450  * before the stop to the station after the stop can't be predicted
1451  * we shouldn't construct it when the vehicle visits the next stop. */
1452  v->last_loading_station = INVALID_STATION;
1453  if (v->owner == _local_company) {
1454  SetDParam(0, v->index);
1455  AddVehicleAdviceNewsItem(STR_NEWS_TRAIN_IS_WAITING + v->type, v->index);
1456  }
1457  AI::NewEvent(v->owner, new ScriptEventVehicleWaitingInDepot(v->index));
1458  }
1459  v->current_order.MakeDummy();
1460  }
1461 }
1462 
1463 
1469 {
1470  UpdateVehicleTileHash(this, false);
1471 }
1472 
1478 void Vehicle::UpdateViewport(bool dirty)
1479 {
1480  int img = this->cur_image;
1481  Point pt = RemapCoords(this->x_pos + this->x_offs, this->y_pos + this->y_offs, this->z_pos);
1482  const Sprite *spr = GetSprite(img, ST_NORMAL);
1483 
1484  pt.x += spr->x_offs;
1485  pt.y += spr->y_offs;
1486 
1487  UpdateVehicleViewportHash(this, pt.x, pt.y);
1488 
1489  Rect old_coord = this->coord;
1490  this->coord.left = pt.x;
1491  this->coord.top = pt.y;
1492  this->coord.right = pt.x + spr->width + 2 * ZOOM_LVL_BASE;
1493  this->coord.bottom = pt.y + spr->height + 2 * ZOOM_LVL_BASE;
1494 
1495  if (dirty) {
1496  if (old_coord.left == INVALID_COORD) {
1497  this->MarkAllViewportsDirty();
1498  } else {
1500  min(old_coord.left, this->coord.left),
1501  min(old_coord.top, this->coord.top),
1502  max(old_coord.right, this->coord.right),
1503  max(old_coord.bottom, this->coord.bottom));
1504  }
1505  }
1506 }
1507 
1512 {
1513  this->UpdatePosition();
1514  this->UpdateViewport(true);
1515 }
1516 
1521 {
1522  ::MarkAllViewportsDirty(this->coord.left, this->coord.top, this->coord.right, this->coord.bottom);
1523 }
1524 
1531 {
1532  static const int8 _delta_coord[16] = {
1533  -1,-1,-1, 0, 1, 1, 1, 0, /* x */
1534  -1, 0, 1, 1, 1, 0,-1,-1, /* y */
1535  };
1536 
1537  int x = v->x_pos + _delta_coord[v->direction];
1538  int y = v->y_pos + _delta_coord[v->direction + 8];
1539 
1541  gp.x = x;
1542  gp.y = y;
1543  gp.old_tile = v->tile;
1544  gp.new_tile = TileVirtXY(x, y);
1545  return gp;
1546 }
1547 
1548 static const Direction _new_direction_table[] = {
1549  DIR_N, DIR_NW, DIR_W,
1550  DIR_NE, DIR_SE, DIR_SW,
1551  DIR_E, DIR_SE, DIR_S
1552 };
1553 
1554 Direction GetDirectionTowards(const Vehicle *v, int x, int y)
1555 {
1556  int i = 0;
1557 
1558  if (y >= v->y_pos) {
1559  if (y != v->y_pos) i += 3;
1560  i += 3;
1561  }
1562 
1563  if (x >= v->x_pos) {
1564  if (x != v->x_pos) i++;
1565  i++;
1566  }
1567 
1568  Direction dir = v->direction;
1569 
1570  DirDiff dirdiff = DirDifference(_new_direction_table[i], dir);
1571  if (dirdiff == DIRDIFF_SAME) return dir;
1572  return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
1573 }
1574 
1585 {
1586  return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
1587 }
1588 
1596 FreeUnitIDGenerator::FreeUnitIDGenerator(VehicleType type, CompanyID owner) : cache(NULL), maxid(0), curid(0)
1597 {
1598  /* Find maximum */
1599  const Vehicle *v;
1600  FOR_ALL_VEHICLES(v) {
1601  if (v->type == type && v->owner == owner) {
1602  this->maxid = max<UnitID>(this->maxid, v->unitnumber);
1603  }
1604  }
1605 
1606  if (this->maxid == 0) return;
1607 
1608  /* Reserving 'maxid + 2' because we need:
1609  * - space for the last item (with v->unitnumber == maxid)
1610  * - one free slot working as loop terminator in FreeUnitIDGenerator::NextID() */
1611  this->cache = CallocT<bool>(this->maxid + 2);
1612 
1613  /* Fill the cache */
1614  FOR_ALL_VEHICLES(v) {
1615  if (v->type == type && v->owner == owner) {
1616  this->cache[v->unitnumber] = true;
1617  }
1618  }
1619 }
1620 
1623 {
1624  if (this->maxid <= this->curid) return ++this->curid;
1625 
1626  while (this->cache[++this->curid]) { } // it will stop, we reserved more space than needed
1627 
1628  return this->curid;
1629 }
1630 
1637 {
1638  /* Check whether it is allowed to build another vehicle. */
1639  uint max_veh;
1640  switch (type) {
1641  case VEH_TRAIN: max_veh = _settings_game.vehicle.max_trains; break;
1642  case VEH_ROAD: max_veh = _settings_game.vehicle.max_roadveh; break;
1643  case VEH_SHIP: max_veh = _settings_game.vehicle.max_ships; break;
1644  case VEH_AIRCRAFT: max_veh = _settings_game.vehicle.max_aircraft; break;
1645  default: NOT_REACHED();
1646  }
1647 
1649  if (c->group_all[type].num_vehicle >= max_veh) return UINT16_MAX; // Currently already at the limit, no room to make a new one.
1650 
1652 
1653  return gen.NextID();
1654 }
1655 
1656 
1666 {
1667  assert(IsCompanyBuildableVehicleType(type));
1668 
1669  if (!Company::IsValidID(_local_company)) return false;
1671 
1672  UnitID max;
1673  switch (type) {
1674  case VEH_TRAIN: max = _settings_game.vehicle.max_trains; break;
1675  case VEH_ROAD: max = _settings_game.vehicle.max_roadveh; break;
1676  case VEH_SHIP: max = _settings_game.vehicle.max_ships; break;
1677  case VEH_AIRCRAFT: max = _settings_game.vehicle.max_aircraft; break;
1678  default: NOT_REACHED();
1679  }
1680 
1681  /* We can build vehicle infrastructure when we may build the vehicle type */
1682  if (max > 0) {
1683  /* Can we actually build the vehicle type? */
1684  const Engine *e;
1685  FOR_ALL_ENGINES_OF_TYPE(e, type) {
1686  if (HasBit(e->company_avail, _local_company)) return true;
1687  }
1688  return false;
1689  }
1690 
1691  /* We should be able to build infrastructure when we have the actual vehicle type */
1692  const Vehicle *v;
1693  FOR_ALL_VEHICLES(v) {
1694  if (v->owner == _local_company && v->type == type) return true;
1695  }
1696 
1697  return false;
1698 }
1699 
1700 
1708 LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
1709 {
1710  CargoID cargo_type = v == NULL ? (CargoID)CT_INVALID : v->cargo_type;
1711  const Engine *e = Engine::Get(engine_type);
1712  switch (e->type) {
1713  default: NOT_REACHED();
1714  case VEH_TRAIN:
1715  if (v != NULL && parent_engine_type != INVALID_ENGINE && (UsesWagonOverride(v) || (v->IsArticulatedPart() && e->u.rail.railveh_type != RAILVEH_WAGON))) {
1716  /* Wagonoverrides use the colour scheme of the front engine.
1717  * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */
1718  engine_type = parent_engine_type;
1719  e = Engine::Get(engine_type);
1720  /* Note: Luckily cargo_type is not needed for engines */
1721  }
1722 
1723  if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
1724  if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
1725  if (e->u.rail.railveh_type == RAILVEH_WAGON) {
1726  if (!CargoSpec::Get(cargo_type)->is_freight) {
1727  if (parent_engine_type == INVALID_ENGINE) {
1728  return LS_PASSENGER_WAGON_STEAM;
1729  } else {
1730  switch (RailVehInfo(parent_engine_type)->engclass) {
1731  default: NOT_REACHED();
1732  case EC_STEAM: return LS_PASSENGER_WAGON_STEAM;
1733  case EC_DIESEL: return LS_PASSENGER_WAGON_DIESEL;
1734  case EC_ELECTRIC: return LS_PASSENGER_WAGON_ELECTRIC;
1735  case EC_MONORAIL: return LS_PASSENGER_WAGON_MONORAIL;
1736  case EC_MAGLEV: return LS_PASSENGER_WAGON_MAGLEV;
1737  }
1738  }
1739  } else {
1740  return LS_FREIGHT_WAGON;
1741  }
1742  } else {
1743  bool is_mu = HasBit(e->info.misc_flags, EF_RAIL_IS_MU);
1744 
1745  switch (e->u.rail.engclass) {
1746  default: NOT_REACHED();
1747  case EC_STEAM: return LS_STEAM;
1748  case EC_DIESEL: return is_mu ? LS_DMU : LS_DIESEL;
1749  case EC_ELECTRIC: return is_mu ? LS_EMU : LS_ELECTRIC;
1750  case EC_MONORAIL: return LS_MONORAIL;
1751  case EC_MAGLEV: return LS_MAGLEV;
1752  }
1753  }
1754 
1755  case VEH_ROAD:
1756  /* Always use the livery of the front */
1757  if (v != NULL && parent_engine_type != INVALID_ENGINE) {
1758  engine_type = parent_engine_type;
1759  e = Engine::Get(engine_type);
1760  cargo_type = v->First()->cargo_type;
1761  }
1762  if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
1763  if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
1764 
1765  /* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */
1766  if (HasBit(e->info.misc_flags, EF_ROAD_TRAM)) {
1767  /* Tram */
1768  return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
1769  } else {
1770  /* Bus or truck */
1771  return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_BUS : LS_TRUCK;
1772  }
1773 
1774  case VEH_SHIP:
1775  if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
1776  if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
1777  return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
1778 
1779  case VEH_AIRCRAFT:
1780  switch (e->u.air.subtype) {
1781  case AIR_HELI: return LS_HELICOPTER;
1782  case AIR_CTOL: return LS_SMALL_PLANE;
1783  case AIR_CTOL | AIR_FAST: return LS_LARGE_PLANE;
1784  default: NOT_REACHED();
1785  }
1786  }
1787 }
1788 
1798 const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, byte livery_setting)
1799 {
1800  const Company *c = Company::Get(company);
1801  LiveryScheme scheme = LS_DEFAULT;
1802 
1803  /* The default livery is always available for use, but its in_use flag determines
1804  * whether any _other_ liveries are in use. */
1805  if (c->livery[LS_DEFAULT].in_use && (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company))) {
1806  /* Determine the livery scheme to use */
1807  scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
1808 
1809  /* Switch back to the default scheme if the resolved scheme is not in use */
1810  if (!c->livery[scheme].in_use) scheme = LS_DEFAULT;
1811  }
1812 
1813  return &c->livery[scheme];
1814 }
1815 
1816 
1817 static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
1818 {
1819  PaletteID map = (v != NULL) ? v->colourmap : PAL_NONE;
1820 
1821  /* Return cached value if any */
1822  if (map != PAL_NONE) return map;
1823 
1824  const Engine *e = Engine::Get(engine_type);
1825 
1826  /* Check if we should use the colour map callback */
1828  uint16 callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
1829  /* Failure means "use the default two-colour" */
1830  if (callback != CALLBACK_FAILED) {
1831  assert_compile(PAL_NONE == 0); // Returning 0x4000 (resp. 0xC000) coincidences with default value (PAL_NONE)
1832  map = GB(callback, 0, 14);
1833  /* If bit 14 is set, then the company colours are applied to the
1834  * map else it's returned as-is. */
1835  if (!HasBit(callback, 14)) {
1836  /* Update cache */
1837  if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
1838  return map;
1839  }
1840  }
1841  }
1842 
1843  bool twocc = HasBit(e->info.misc_flags, EF_USES_2CC);
1844 
1845  if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
1846 
1847  /* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
1848  if (!Company::IsValidID(company)) return map;
1849 
1850  const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries);
1851 
1852  map += livery->colour1;
1853  if (twocc) map += livery->colour2 * 16;
1854 
1855  /* Update cache */
1856  if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
1857  return map;
1858 }
1859 
1867 {
1868  return GetEngineColourMap(engine_type, company, INVALID_ENGINE, NULL);
1869 }
1870 
1877 {
1878  if (v->IsGroundVehicle()) {
1879  return GetEngineColourMap(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v);
1880  }
1881 
1882  return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
1883 }
1884 
1889 {
1890  if (this->IsGroundVehicle()) {
1891  uint16 &gv_flags = this->GetGroundVehicleFlags();
1892  if (HasBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS)) {
1893  /* Do not delete orders, only skip them */
1896  InvalidateVehicleOrder(this, 0);
1897  return;
1898  }
1899  }
1900 
1901  const Order *order = this->GetOrder(this->cur_implicit_order_index);
1902  while (order != NULL) {
1903  if (this->cur_implicit_order_index == this->cur_real_order_index) break;
1904 
1905  if (order->IsType(OT_IMPLICIT)) {
1907  /* DeleteOrder does various magic with order_indices, so resync 'order' with 'cur_implicit_order_index' */
1908  order = this->GetOrder(this->cur_implicit_order_index);
1909  } else {
1910  /* Skip non-implicit orders, e.g. service-orders */
1911  order = order->next;
1912  this->cur_implicit_order_index++;
1913  }
1914 
1915  /* Wrap around */
1916  if (order == NULL) {
1917  order = this->GetOrder(0);
1918  this->cur_implicit_order_index = 0;
1919  }
1920  }
1921 }
1922 
1928 {
1929  assert(IsTileType(this->tile, MP_STATION) || this->type == VEH_SHIP);
1930 
1931  if (this->current_order.IsType(OT_GOTO_STATION) &&
1934 
1935  /* Now both order indices point to the destination station, and we can start loading */
1936  this->current_order.MakeLoading(true);
1937  UpdateVehicleTimetable(this, true);
1938 
1939  /* Furthermore add the Non Stop flag to mark that this station
1940  * is the actual destination of the vehicle, which is (for example)
1941  * necessary to be known for HandleTrainLoading to determine
1942  * whether the train is lost or not; not marking a train lost
1943  * that arrives at random stations is bad. */
1945 
1946  } else {
1947  /* We weren't scheduled to stop here. Insert an implicit order
1948  * to show that we are stopping here.
1949  * While only groundvehicles have implicit orders, e.g. aircraft might still enter
1950  * the 'wrong' terminal when skipping orders etc. */
1951  Order *in_list = this->GetOrder(this->cur_implicit_order_index);
1952  if (this->IsGroundVehicle() &&
1953  (in_list == NULL || !in_list->IsType(OT_IMPLICIT) ||
1954  in_list->GetDestination() != this->last_station_visited)) {
1955  bool suppress_implicit_orders = HasBit(this->GetGroundVehicleFlags(), GVF_SUPPRESS_IMPLICIT_ORDERS);
1956  /* Do not create consecutive duplicates of implicit orders */
1957  Order *prev_order = this->cur_implicit_order_index > 0 ? this->GetOrder(this->cur_implicit_order_index - 1) : (this->GetNumOrders() > 1 ? this->GetLastOrder() : NULL);
1958  if (prev_order == NULL ||
1959  (!prev_order->IsType(OT_IMPLICIT) && !prev_order->IsType(OT_GOTO_STATION)) ||
1960  prev_order->GetDestination() != this->last_station_visited) {
1961 
1962  /* Prefer deleting implicit orders instead of inserting new ones,
1963  * so test whether the right order follows later. In case of only
1964  * implicit orders treat the last order in the list like an
1965  * explicit one, except if the overall number of orders surpasses
1966  * IMPLICIT_ORDER_ONLY_CAP. */
1967  int target_index = this->cur_implicit_order_index;
1968  bool found = false;
1969  while (target_index != this->cur_real_order_index || this->GetNumManualOrders() == 0) {
1970  const Order *order = this->GetOrder(target_index);
1971  if (order == NULL) break; // No orders.
1972  if (order->IsType(OT_IMPLICIT) && order->GetDestination() == this->last_station_visited) {
1973  found = true;
1974  break;
1975  }
1976  target_index++;
1977  if (target_index >= this->orders.list->GetNumOrders()) {
1978  if (this->GetNumManualOrders() == 0 &&
1980  break;
1981  }
1982  target_index = 0;
1983  }
1984  if (target_index == this->cur_implicit_order_index) break; // Avoid infinite loop.
1985  }
1986 
1987  if (found) {
1988  if (suppress_implicit_orders) {
1989  /* Skip to the found order */
1990  this->cur_implicit_order_index = target_index;
1991  InvalidateVehicleOrder(this, 0);
1992  } else {
1993  /* Delete all implicit orders up to the station we just reached */
1994  const Order *order = this->GetOrder(this->cur_implicit_order_index);
1995  while (!order->IsType(OT_IMPLICIT) || order->GetDestination() != this->last_station_visited) {
1996  if (order->IsType(OT_IMPLICIT)) {
1998  /* DeleteOrder does various magic with order_indices, so resync 'order' with 'cur_implicit_order_index' */
1999  order = this->GetOrder(this->cur_implicit_order_index);
2000  } else {
2001  /* Skip non-implicit orders, e.g. service-orders */
2002  order = order->next;
2003  this->cur_implicit_order_index++;
2004  }
2005 
2006  /* Wrap around */
2007  if (order == NULL) {
2008  order = this->GetOrder(0);
2009  this->cur_implicit_order_index = 0;
2010  }
2011  assert(order != NULL);
2012  }
2013  }
2014  } else if (!suppress_implicit_orders &&
2015  ((this->orders.list == NULL ? OrderList::CanAllocateItem() : this->orders.list->GetNumOrders() < MAX_VEH_ORDER_ID)) &&
2017  /* Insert new implicit order */
2018  Order *implicit_order = new Order();
2019  implicit_order->MakeImplicit(this->last_station_visited);
2020  InsertOrder(this, implicit_order, this->cur_implicit_order_index);
2021  if (this->cur_implicit_order_index > 0) --this->cur_implicit_order_index;
2022 
2023  /* InsertOrder disabled creation of implicit orders for all vehicles with the same implicit order.
2024  * Reenable it for this vehicle */
2025  uint16 &gv_flags = this->GetGroundVehicleFlags();
2027  }
2028  }
2029  }
2030  this->current_order.MakeLoading(false);
2031  }
2032 
2033  if (this->last_loading_station != INVALID_STATION &&
2034  this->last_loading_station != this->last_station_visited &&
2035  ((this->current_order.GetLoadType() & OLFB_NO_LOAD) == 0 ||
2036  (this->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0)) {
2038  }
2039 
2040  PrepareUnload(this);
2041 
2046 
2047  Station::Get(this->last_station_visited)->MarkTilesDirty(true);
2048  this->cur_speed = 0;
2049  this->MarkDirty();
2050 }
2051 
2057 void Vehicle::CancelReservation(StationID next, Station *st)
2058 {
2059  for (Vehicle *v = this; v != NULL; v = v->next) {
2061  if (cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0) {
2062  DEBUG(misc, 1, "cancelling cargo reservation");
2063  cargo.Return(UINT_MAX, &st->goods[v->cargo_type].cargo, next);
2064  cargo.SetTransferLoadPlace(st->xy);
2065  }
2066  cargo.KeepAll();
2067  }
2068 }
2069 
2075 {
2076  assert(this->current_order.IsType(OT_LOADING));
2077 
2078  delete this->cargo_payment;
2079 
2080  /* Only update the timetable if the vehicle was supposed to stop here. */
2082 
2083  if ((this->current_order.GetLoadType() & OLFB_NO_LOAD) == 0 ||
2084  (this->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) {
2085  if (this->current_order.CanLeaveWithCargo(this->last_loading_station != INVALID_STATION)) {
2086  /* Refresh next hop stats to make sure we've done that at least once
2087  * during the stop and that refit_cap == cargo_cap for each vehicle in
2088  * the consist. */
2089  this->ResetRefitCaps();
2090  LinkRefresher::Run(this);
2091 
2092  /* if the vehicle could load here or could stop with cargo loaded set the last loading station */
2094  } else {
2095  /* if the vehicle couldn't load and had to unload or transfer everything
2096  * set the last loading station to invalid as it will leave empty. */
2097  this->last_loading_station = INVALID_STATION;
2098  }
2099  }
2100 
2103  this->CancelReservation(INVALID_STATION, st);
2104  st->loading_vehicles.remove(this);
2105 
2107 
2108  if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) {
2109  /* Trigger station animation (trains only) */
2110  if (IsTileType(this->tile, MP_STATION)) {
2112  TriggerStationAnimation(st, this->tile, SAT_TRAIN_DEPARTS);
2113  }
2114 
2115  SetBit(Train::From(this)->flags, VRF_LEAVING_STATION);
2116  }
2117 
2118  this->MarkDirty();
2119 }
2120 
2125 {
2126  for (Vehicle *v = this; v != NULL; v = v->Next()) v->refit_cap = v->cargo_cap;
2127 }
2128 
2134 void Vehicle::HandleLoading(bool mode)
2135 {
2136  switch (this->current_order.GetType()) {
2137  case OT_LOADING: {
2138  uint wait_time = max(this->current_order.GetTimetabledWait() - this->lateness_counter, 0);
2139 
2140  /* Not the first call for this tick, or still loading */
2141  if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || this->current_order_time < wait_time) return;
2142 
2143  this->PlayLeaveStationSound();
2144 
2145  this->LeaveStation();
2146 
2147  /* Only advance to next order if we just loaded at the current one */
2148  const Order *order = this->GetOrder(this->cur_implicit_order_index);
2149  if (order == NULL ||
2150  (!order->IsType(OT_IMPLICIT) && !order->IsType(OT_GOTO_STATION)) ||
2151  order->GetDestination() != this->last_station_visited) {
2152  return;
2153  }
2154  break;
2155  }
2156 
2157  case OT_DUMMY: break;
2158 
2159  default: return;
2160  }
2161 
2163 }
2164 
2170 {
2171  for (const Vehicle *v = this; v != NULL; v = v->Next()) {
2172  if (v->cargo_cap == 0) continue;
2173  SmallPair<CargoID, uint> *pair = capacities.Find(v->cargo_type);
2174  if (pair == capacities.End()) {
2175  pair = capacities.Append();
2176  pair->first = v->cargo_type;
2177  pair->second = v->cargo_cap - v->cargo.StoredCount();
2178  } else {
2179  pair->second += v->cargo_cap - v->cargo.StoredCount();
2180  }
2181  }
2182 }
2183 
2184 uint Vehicle::GetConsistTotalCapacity() const
2185 {
2186  uint result = 0;
2187  for (const Vehicle *v = this; v != NULL; v = v->Next()) {
2188  result += v->cargo_cap;
2189  }
2190  return result;
2191 }
2192 
2200 {
2201  CommandCost ret = CheckOwnership(this->owner);
2202  if (ret.Failed()) return ret;
2203 
2204  if (this->vehstatus & VS_CRASHED) return CMD_ERROR;
2205  if (this->IsStoppedInDepot()) return CMD_ERROR;
2206 
2207  if (this->current_order.IsType(OT_GOTO_DEPOT)) {
2208  bool halt_in_depot = (this->current_order.GetDepotActionType() & ODATFB_HALT) != 0;
2209  if (!!(command & DEPOT_SERVICE) == halt_in_depot) {
2210  /* We called with a different DEPOT_SERVICE setting.
2211  * Now we change the setting to apply the new one and let the vehicle head for the same depot.
2212  * Note: the if is (true for requesting service == true for ordered to stop in depot) */
2213  if (flags & DC_EXEC) {
2217  }
2218  return CommandCost();
2219  }
2220 
2221  if (command & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
2222  if (flags & DC_EXEC) {
2223  /* If the orders to 'goto depot' are in the orders list (forced servicing),
2224  * then skip to the next order; effectively cancelling this forced service */
2226 
2227  if (this->IsGroundVehicle()) {
2228  uint16 &gv_flags = this->GetGroundVehicleFlags();
2230  }
2231 
2232  this->current_order.MakeDummy();
2234  }
2235  return CommandCost();
2236  }
2237 
2238  TileIndex location;
2239  DestinationID destination;
2240  bool reverse;
2241  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};
2242  if (!this->FindClosestDepot(&location, &destination, &reverse)) return_cmd_error(no_depot[this->type]);
2243 
2244  if (flags & DC_EXEC) {
2245  if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
2246 
2247  if (this->IsGroundVehicle() && this->GetNumManualOrders() > 0) {
2248  uint16 &gv_flags = this->GetGroundVehicleFlags();
2250  }
2251 
2252  this->dest_tile = location;
2253  this->current_order.MakeGoToDepot(destination, ODTF_MANUAL);
2254  if (!(command & DEPOT_SERVICE)) this->current_order.SetDepotActionType(ODATFB_HALT);
2256 
2257  /* If there is no depot in front, reverse automatically (trains only) */
2258  if (this->type == VEH_TRAIN && reverse) DoCommand(this->tile, this->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
2259 
2260  if (this->type == VEH_AIRCRAFT) {
2261  Aircraft *a = Aircraft::From(this);
2262  if (a->state == FLYING && a->targetairport != destination) {
2263  /* The aircraft is now heading for a different hangar than the next in the orders */
2266  }
2267  }
2268  }
2269 
2270  return CommandCost();
2271 
2272 }
2273 
2278 void Vehicle::UpdateVisualEffect(bool allow_power_change)
2279 {
2280  bool powered_before = HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
2281  const Engine *e = this->GetEngine();
2282 
2283  /* Evaluate properties */
2284  byte visual_effect;
2285  switch (e->type) {
2286  case VEH_TRAIN: visual_effect = e->u.rail.visual_effect; break;
2287  case VEH_ROAD: visual_effect = e->u.road.visual_effect; break;
2288  case VEH_SHIP: visual_effect = e->u.ship.visual_effect; break;
2289  default: visual_effect = 1 << VE_DISABLE_EFFECT; break;
2290  }
2291 
2292  /* Check powered wagon / visual effect callback */
2294  uint16 callback = GetVehicleCallback(CBID_VEHICLE_VISUAL_EFFECT, 0, 0, this->engine_type, this);
2295 
2296  if (callback != CALLBACK_FAILED) {
2297  if (callback >= 0x100 && e->GetGRF()->grf_version >= 8) ErrorUnknownCallbackResult(e->GetGRFID(), CBID_VEHICLE_VISUAL_EFFECT, callback);
2298 
2299  callback = GB(callback, 0, 8);
2300  /* Avoid accidentally setting 'visual_effect' to the default value
2301  * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
2302  if (callback == VE_DEFAULT) {
2303  assert(HasBit(callback, VE_DISABLE_EFFECT));
2304  SB(callback, VE_TYPE_START, VE_TYPE_COUNT, 0);
2305  }
2306  visual_effect = callback;
2307  }
2308  }
2309 
2310  /* Apply default values */
2311  if (visual_effect == VE_DEFAULT ||
2312  (!HasBit(visual_effect, VE_DISABLE_EFFECT) && GB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT) == VE_TYPE_DEFAULT)) {
2313  /* Only train engines have default effects.
2314  * Note: This is independent of whether the engine is a front engine or articulated part or whatever. */
2315  if (e->type != VEH_TRAIN || e->u.rail.railveh_type == RAILVEH_WAGON || !IsInsideMM(e->u.rail.engclass, EC_STEAM, EC_MONORAIL)) {
2316  if (visual_effect == VE_DEFAULT) {
2317  visual_effect = 1 << VE_DISABLE_EFFECT;
2318  } else {
2319  SetBit(visual_effect, VE_DISABLE_EFFECT);
2320  }
2321  } else {
2322  if (visual_effect == VE_DEFAULT) {
2323  /* Also set the offset */
2324  visual_effect = (VE_OFFSET_CENTRE - (e->u.rail.engclass == EC_STEAM ? 4 : 0)) << VE_OFFSET_START;
2325  }
2326  SB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT, e->u.rail.engclass - EC_STEAM + VE_TYPE_STEAM);
2327  }
2328  }
2329 
2330  this->vcache.cached_vis_effect = visual_effect;
2331 
2332  if (!allow_power_change && powered_before != HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
2334  ShowNewGrfVehicleError(this->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_POWERED_WAGON, GBUG_VEH_POWERED_WAGON, false);
2335  }
2336 }
2337 
2338 static const int8 _vehicle_smoke_pos[8] = {
2339  1, 1, 1, 0, -1, -1, -1, 0
2340 };
2341 
2346 static void SpawnAdvancedVisualEffect(const Vehicle *v)
2347 {
2348  uint16 callback = GetVehicleCallback(CBID_VEHICLE_SPAWN_VISUAL_EFFECT, 0, Random(), v->engine_type, v);
2349  if (callback == CALLBACK_FAILED) return;
2350 
2351  uint count = GB(callback, 0, 2);
2352  bool auto_center = HasBit(callback, 13);
2353  bool auto_rotate = !HasBit(callback, 14);
2354 
2355  int8 l_center = 0;
2356  if (auto_center) {
2357  /* For road vehicles: Compute offset from vehicle position to vehicle center */
2358  if (v->type == VEH_ROAD) l_center = -(int)(VEHICLE_LENGTH - RoadVehicle::From(v)->gcache.cached_veh_length) / 2;
2359  } else {
2360  /* For trains: Compute offset from vehicle position to sprite position */
2361  if (v->type == VEH_TRAIN) l_center = (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
2362  }
2363 
2364  Direction l_dir = v->direction;
2365  if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) l_dir = ReverseDir(l_dir);
2366  Direction t_dir = ChangeDir(l_dir, DIRDIFF_90RIGHT);
2367 
2368  int8 x_center = _vehicle_smoke_pos[l_dir] * l_center;
2369  int8 y_center = _vehicle_smoke_pos[t_dir] * l_center;
2370 
2371  for (uint i = 0; i < count; i++) {
2372  uint32 reg = GetRegister(0x100 + i);
2373  uint type = GB(reg, 0, 8);
2374  int8 x = GB(reg, 8, 8);
2375  int8 y = GB(reg, 16, 8);
2376  int8 z = GB(reg, 24, 8);
2377 
2378  if (auto_rotate) {
2379  int8 l = x;
2380  int8 t = y;
2381  x = _vehicle_smoke_pos[l_dir] * l + _vehicle_smoke_pos[t_dir] * t;
2382  y = _vehicle_smoke_pos[t_dir] * l - _vehicle_smoke_pos[l_dir] * t;
2383  }
2384 
2385  if (type >= 0xF0) {
2386  switch (type) {
2387  case 0xF1: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_STEAM_SMOKE); break;
2388  case 0xF2: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_DIESEL_SMOKE); break;
2389  case 0xF3: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_ELECTRIC_SPARK); break;
2390  case 0xFA: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_BREAKDOWN_SMOKE_AIRCRAFT); break;
2391  default: break;
2392  }
2393  }
2394  }
2395 }
2396 
2402 {
2403  assert(this->IsPrimaryVehicle());
2404  bool sound = false;
2405 
2406  /* Do not show any smoke when:
2407  * - vehicle smoke is disabled by the player
2408  * - the vehicle is slowing down or stopped (by the player)
2409  * - the vehicle is moving very slowly
2410  */
2411  if (_settings_game.vehicle.smoke_amount == 0 ||
2412  this->vehstatus & (VS_TRAIN_SLOWING | VS_STOPPED) ||
2413  this->cur_speed < 2) {
2414  return;
2415  }
2416 
2417  uint max_speed = this->vcache.cached_max_speed;
2418  if (this->type == VEH_TRAIN) {
2419  const Train *t = Train::From(this);
2420  /* For trains, do not show any smoke when:
2421  * - the train is reversing
2422  * - is entering a station with an order to stop there and its speed is equal to maximum station entering speed
2423  */
2424  if (HasBit(t->flags, VRF_REVERSING) ||
2426  t->cur_speed >= t->Train::GetCurrentMaxSpeed())) {
2427  return;
2428  }
2429 
2430  max_speed = min(max_speed, t->gcache.cached_max_track_speed);
2431  max_speed = min(max_speed, this->current_order.GetMaxSpeed());
2432  }
2433  if (this->type == VEH_ROAD || this->type == VEH_SHIP) max_speed = min(max_speed, this->current_order.GetMaxSpeed() * 2);
2434 
2435  const Vehicle *v = this;
2436 
2437  do {
2438  bool advanced = HasBit(v->vcache.cached_vis_effect, VE_ADVANCED_EFFECT);
2439  int effect_offset = GB(v->vcache.cached_vis_effect, VE_OFFSET_START, VE_OFFSET_COUNT) - VE_OFFSET_CENTRE;
2440  VisualEffectSpawnModel effect_model = VESM_NONE;
2441  if (advanced) {
2442  effect_offset = VE_OFFSET_CENTRE;
2443  effect_model = (VisualEffectSpawnModel)GB(v->vcache.cached_vis_effect, 0, VE_ADVANCED_EFFECT);
2444  if (effect_model >= VESM_END) effect_model = VESM_NONE; // unknown spawning model
2445  } else {
2446  effect_model = (VisualEffectSpawnModel)GB(v->vcache.cached_vis_effect, VE_TYPE_START, VE_TYPE_COUNT);
2447  assert(effect_model != (VisualEffectSpawnModel)VE_TYPE_DEFAULT); // should have been resolved by UpdateVisualEffect
2448  assert_compile((uint)VESM_STEAM == (uint)VE_TYPE_STEAM);
2449  assert_compile((uint)VESM_DIESEL == (uint)VE_TYPE_DIESEL);
2450  assert_compile((uint)VESM_ELECTRIC == (uint)VE_TYPE_ELECTRIC);
2451  }
2452 
2453  /* Show no smoke when:
2454  * - Smoke has been disabled for this vehicle
2455  * - The vehicle is not visible
2456  * - The vehicle is under a bridge
2457  * - The vehicle is on a depot tile
2458  * - The vehicle is on a tunnel tile
2459  * - The vehicle is a train engine that is currently unpowered */
2460  if (effect_model == VESM_NONE ||
2461  v->vehstatus & VS_HIDDEN ||
2462  IsBridgeAbove(v->tile) ||
2463  IsDepotTile(v->tile) ||
2464  IsTunnelTile(v->tile) ||
2465  (v->type == VEH_TRAIN &&
2466  !HasPowerOnRail(Train::From(v)->railtype, GetTileRailType(v->tile)))) {
2467  continue;
2468  }
2469 
2470  EffectVehicleType evt = EV_END;
2471  switch (effect_model) {
2472  case VESM_STEAM:
2473  /* Steam smoke - amount is gradually falling until vehicle reaches its maximum speed, after that it's normal.
2474  * Details: while vehicle's current speed is gradually increasing, steam plumes' density decreases by one third each
2475  * third of its maximum speed spectrum. Steam emission finally normalises at very close to vehicle's maximum speed.
2476  * REGULATION:
2477  * - instead of 1, 4 / 2^smoke_amount (max. 2) is used to provide sufficient regulation to steam puffs' amount. */
2478  if (GB(v->tick_counter, 0, ((4 >> _settings_game.vehicle.smoke_amount) + ((this->cur_speed * 3) / max_speed))) == 0) {
2479  evt = EV_STEAM_SMOKE;
2480  }
2481  break;
2482 
2483  case VESM_DIESEL: {
2484  /* Diesel smoke - thicker when vehicle is starting, gradually subsiding till it reaches its maximum speed
2485  * when smoke emission stops.
2486  * Details: Vehicle's (max.) speed spectrum is divided into 32 parts. When max. speed is reached, chance for smoke
2487  * emission erodes by 32 (1/4). For trains, power and weight come in handy too to either increase smoke emission in
2488  * 6 steps (1000HP each) if the power is low or decrease smoke emission in 6 steps (512 tonnes each) if the train
2489  * isn't overweight. Power and weight contributions are expressed in a way that neither extreme power, nor
2490  * extreme weight can ruin the balance (e.g. FreightWagonMultiplier) in the formula. When the vehicle reaches
2491  * maximum speed no diesel_smoke is emitted.
2492  * REGULATION:
2493  * - up to which speed a diesel vehicle is emitting smoke (with reduced/small setting only until 1/2 of max_speed),
2494  * - in Chance16 - the last value is 512 / 2^smoke_amount (max. smoke when 128 = smoke_amount of 2). */
2495  int power_weight_effect = 0;
2496  if (v->type == VEH_TRAIN) {
2497  power_weight_effect = (32 >> (Train::From(this)->gcache.cached_power >> 10)) - (32 >> (Train::From(this)->gcache.cached_weight >> 9));
2498  }
2499  if (this->cur_speed < (max_speed >> (2 >> _settings_game.vehicle.smoke_amount)) &&
2500  Chance16((64 - ((this->cur_speed << 5) / max_speed) + power_weight_effect), (512 >> _settings_game.vehicle.smoke_amount))) {
2501  evt = EV_DIESEL_SMOKE;
2502  }
2503  break;
2504  }
2505 
2506  case VESM_ELECTRIC:
2507  /* Electric train's spark - more often occurs when train is departing (more load)
2508  * Details: Electric locomotives are usually at least twice as powerful as their diesel counterparts, so spark
2509  * emissions are kept simple. Only when starting, creating huge force are sparks more likely to happen, but when
2510  * reaching its max. speed, quarter by quarter of it, chance decreases until the usual 2,22% at train's top speed.
2511  * REGULATION:
2512  * - in Chance16 the last value is 360 / 2^smoke_amount (max. sparks when 90 = smoke_amount of 2). */
2513  if (GB(v->tick_counter, 0, 2) == 0 &&
2514  Chance16((6 - ((this->cur_speed << 2) / max_speed)), (360 >> _settings_game.vehicle.smoke_amount))) {
2515  evt = EV_ELECTRIC_SPARK;
2516  }
2517  break;
2518 
2519  default:
2520  NOT_REACHED();
2521  }
2522 
2523  if (evt != EV_END && advanced) {
2524  sound = true;
2526  } else if (evt != EV_END) {
2527  sound = true;
2528 
2529  /* The effect offset is relative to a point 4 units behind the vehicle's
2530  * front (which is the center of an 8/8 vehicle). Shorter vehicles need a
2531  * correction factor. */
2532  if (v->type == VEH_TRAIN) effect_offset += (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
2533 
2534  int x = _vehicle_smoke_pos[v->direction] * effect_offset;
2535  int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
2536 
2537  if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) {
2538  x = -x;
2539  y = -y;
2540  }
2541 
2542  CreateEffectVehicleRel(v, x, y, 10, evt);
2543  }
2544  } while ((v = v->Next()) != NULL);
2545 
2546  if (sound) PlayVehicleSound(this, VSE_VISUAL_EFFECT);
2547 }
2548 
2554 {
2555  assert(this != next);
2556 
2557  if (this->next != NULL) {
2558  /* We had an old next vehicle. Update the first and previous pointers */
2559  for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
2560  v->first = this->next;
2561  }
2562  this->next->previous = NULL;
2563  }
2564 
2565  this->next = next;
2566 
2567  if (this->next != NULL) {
2568  /* A new next vehicle. Update the first and previous pointers */
2569  if (this->next->previous != NULL) this->next->previous->next = NULL;
2570  this->next->previous = this;
2571  for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
2572  v->first = this->first;
2573  }
2574  }
2575 }
2576 
2582 void Vehicle::AddToShared(Vehicle *shared_chain)
2583 {
2584  assert(this->previous_shared == NULL && this->next_shared == NULL);
2585 
2586  if (shared_chain->orders.list == NULL) {
2587  assert(shared_chain->previous_shared == NULL);
2588  assert(shared_chain->next_shared == NULL);
2589  this->orders.list = shared_chain->orders.list = new OrderList(NULL, shared_chain);
2590  }
2591 
2592  this->next_shared = shared_chain->next_shared;
2593  this->previous_shared = shared_chain;
2594 
2595  shared_chain->next_shared = this;
2596 
2597  if (this->next_shared != NULL) this->next_shared->previous_shared = this;
2598 
2599  shared_chain->orders.list->AddVehicle(this);
2600 }
2601 
2606 {
2607  /* Remember if we were first and the old window number before RemoveVehicle()
2608  * as this changes first if needed. */
2609  bool were_first = (this->FirstShared() == this);
2610  VehicleListIdentifier vli(VL_SHARED_ORDERS, this->type, this->owner, this->FirstShared()->index);
2611 
2612  this->orders.list->RemoveVehicle(this);
2613 
2614  if (!were_first) {
2615  /* We are not the first shared one, so only relink our previous one. */
2616  this->previous_shared->next_shared = this->NextShared();
2617  }
2618 
2619  if (this->next_shared != NULL) this->next_shared->previous_shared = this->previous_shared;
2620 
2621 
2622  if (this->orders.list->GetNumVehicles() == 1) {
2623  /* When there is only one vehicle, remove the shared order list window. */
2625  InvalidateVehicleOrder(this->FirstShared(), 0);
2626  } else if (were_first) {
2627  /* If we were the first one, update to the new first one.
2628  * Note: FirstShared() is already the new first */
2629  InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.Pack(), this->FirstShared()->index | (1U << 31));
2630  }
2631 
2632  this->next_shared = NULL;
2633  this->previous_shared = NULL;
2634 }
2635 
2636 void VehiclesYearlyLoop()
2637 {
2638  Vehicle *v;
2639  FOR_ALL_VEHICLES(v) {
2640  if (v->IsPrimaryVehicle()) {
2641  /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
2642  Money profit = v->GetDisplayProfitThisYear();
2643  if (v->age >= 730 && profit < 0) {
2645  SetDParam(0, v->index);
2646  SetDParam(1, profit);
2647  AddVehicleAdviceNewsItem(STR_NEWS_VEHICLE_IS_UNPROFITABLE, v->index);
2648  }
2649  AI::NewEvent(v->owner, new ScriptEventVehicleUnprofitable(v->index));
2650  }
2651 
2653  v->profit_this_year = 0;
2655  }
2656  }
2662 }
2663 
2664 
2674 bool CanVehicleUseStation(EngineID engine_type, const Station *st)
2675 {
2676  const Engine *e = Engine::GetIfValid(engine_type);
2677  assert(e != NULL);
2678 
2679  switch (e->type) {
2680  case VEH_TRAIN:
2681  return (st->facilities & FACIL_TRAIN) != 0;
2682 
2683  case VEH_ROAD:
2684  /* For road vehicles we need the vehicle to know whether it can actually
2685  * use the station, but if it doesn't have facilities for RVs it is
2686  * certainly not possible that the station can be used. */
2687  return (st->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP)) != 0;
2688 
2689  case VEH_SHIP:
2690  return (st->facilities & FACIL_DOCK) != 0;
2691 
2692  case VEH_AIRCRAFT:
2693  return (st->facilities & FACIL_AIRPORT) != 0 &&
2695 
2696  default:
2697  return false;
2698  }
2699 }
2700 
2707 bool CanVehicleUseStation(const Vehicle *v, const Station *st)
2708 {
2709  if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != NULL;
2710 
2711  return CanVehicleUseStation(v->engine_type, st);
2712 }
2713 
2720 {
2721  assert(this->IsGroundVehicle());
2722  if (this->type == VEH_TRAIN) {
2723  return &Train::From(this)->gcache;
2724  } else {
2725  return &RoadVehicle::From(this)->gcache;
2726  }
2727 }
2728 
2735 {
2736  assert(this->IsGroundVehicle());
2737  if (this->type == VEH_TRAIN) {
2738  return &Train::From(this)->gcache;
2739  } else {
2740  return &RoadVehicle::From(this)->gcache;
2741  }
2742 }
2743 
2750 {
2751  assert(this->IsGroundVehicle());
2752  if (this->type == VEH_TRAIN) {
2753  return Train::From(this)->gv_flags;
2754  } else {
2755  return RoadVehicle::From(this)->gv_flags;
2756  }
2757 }
2758 
2764 const uint16 &Vehicle::GetGroundVehicleFlags() const
2765 {
2766  assert(this->IsGroundVehicle());
2767  if (this->type == VEH_TRAIN) {
2768  return Train::From(this)->gv_flags;
2769  } else {
2770  return RoadVehicle::From(this)->gv_flags;
2771  }
2772 }
2773 
2782 void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8 num_vehicles)
2783 {
2784  if (v->type == VEH_TRAIN) {
2785  Train *u = Train::From(v);
2786  /* Only include whole vehicles, so start with the first articulated part */
2787  u = u->GetFirstEnginePart();
2788 
2789  /* Include num_vehicles vehicles, not counting articulated parts */
2790  for (; u != NULL && num_vehicles > 0; num_vehicles--) {
2791  do {
2792  /* Include current vehicle in the selection. */
2793  set.Include(u->index);
2794 
2795  /* If the vehicle is multiheaded, add the other part too. */
2796  if (u->IsMultiheaded()) set.Include(u->other_multiheaded_part->index);
2797 
2798  u = u->Next();
2799  } while (u != NULL && u->IsArticulatedPart());
2800  }
2801  }
2802 }