# vehicle.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * 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.
    00006  * 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.
    00007  * 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/>.
    00008  */
    00009
    00012 #include "stdafx.h"
    00013 #include "gui.h"
    00014 #include "roadveh.h"
    00015 #include "ship.h"
    00016 #include "spritecache.h"
    00017 #include "timetable.h"
    00018 #include "viewport_func.h"
    00019 #include "news_func.h"
    00020 #include "command_func.h"
    00021 #include "company_func.h"
    00022 #include "vehicle_gui.h"
    00023 #include "train.h"
    00024 #include "aircraft.h"
    00025 #include "newgrf_debug.h"
    00026 #include "newgrf_sound.h"
    00027 #include "newgrf_station.h"
    00028 #include "group.h"
    00029 #include "group_gui.h"
    00030 #include "strings_func.h"
    00031 #include "zoom_func.h"
    00032 #include "date_func.h"
    00033 #include "window_func.h"
    00034 #include "vehicle_func.h"
    00035 #include "autoreplace_func.h"
    00036 #include "autoreplace_gui.h"
    00037 #include "station_base.h"
    00038 #include "ai/ai.hpp"
    00039 #include "depot_func.h"
    00040 #include "network/network.h"
    00041 #include "core/pool_func.hpp"
    00042 #include "economy_base.h"
    00043 #include "articulated_vehicles.h"
    00044 #include "roadstop_base.h"
    00045 #include "core/random_func.hpp"
    00046 #include "core/backup_type.hpp"
    00047 #include "order_backup.h"
    00048 #include "sound_func.h"
    00049 #include "effectvehicle_func.h"
    00050 #include "effectvehicle_base.h"
    00051 #include "vehiclelist.h"
    00052 #include "bridge_map.h"
    00053 #include "tunnel_map.h"
    00054 #include "depot_map.h"
    00055 #include "infrastructure_func.h"
    00056
    00057 #include "table/strings.h"
    00058
    00059 #define GEN_HASH(x, y) ((GB((y), 6, 6) << 6) + GB((x), 7, 6))
    00060
    00061 VehicleID _new_vehicle_id;
    00062 uint16 _returned_refit_capacity;
    00063 uint16 _returned_mail_refit_capacity;
    00064 byte _age_cargo_skip_counter;
    00065
    00066
    00068 VehiclePool _vehicle_pool("Vehicle");
    00069 INSTANTIATE_POOL_METHODS(Vehicle)
    00070
    00071
    00076 bool Vehicle::NeedsAutorenewing(const Company *c) const
    00077 {
    00078   /* We can always generate the Company pointer when we have the vehicle.
    00079    * However this takes time and since the Company pointer is often present
    00080    * when this function is called then it's faster to pass the pointer as an
    00081    * argument rather than finding it again. */
    00082   assert(c == Company::Get(this->owner));
    00083
    00084   if (!c->settings.engine_renew) return false;
    00085   if (this->age - this->max_age < (c->settings.engine_renew_months * 30)) return false;
    00086   if (this->age == 0) return false; // rail cars don't age and lacks a max age
    00087
    00088   return true;
    00089 }
    00090
    00091 void VehicleServiceInDepot(Vehicle *v)
    00092 {
    00093   const Engine *e = Engine::Get(v->engine_type);
    00094   if (v->type == VEH_TRAIN) {
    00095     if (v->Next() != NULL) VehicleServiceInDepot(v->Next());
    00096     if (!(Train::From(v)->IsEngine()) && !(Train::From(v)->IsRearDualheaded())) return;
    00097     ClrBit(Train::From(v)->flags,VRF_NEED_REPAIR);
    00098     const RailVehicleInfo *rvi = &e->u.rail;
    00099     v->vcache.cached_max_speed = rvi->max_speed;
    00100     if (Train::From(v)->IsFrontEngine()) {
    00101       Train::From(v)->ConsistChanged(true);
    00102       CLRBITS(Train::From(v)->flags, (1 << VRF_BREAKDOWN_BRAKING) | VRF_IS_BROKEN );
    00103     }
    00104   }
    00105   v->date_of_last_service = _date;
    00106   v->breakdowns_since_last_service = 0;
    00107   v->reliability = e->reliability;
    00108   v->breakdown_ctr = 0;
    00109   v->vehstatus &= ~VS_AIRCRAFT_BROKEN;
    00110   SetWindowDirty(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
    00111 }
    00112
    00119 bool Vehicle::NeedsServicing() const
    00120 {
    00121   /* Stopped or crashed vehicles will not move, as such making unmovable
    00122    * vehicles to go for service is lame. */
    00123   if (this->vehstatus & (VS_STOPPED | VS_CRASHED)) return false;
    00124
    00125   /* Are we ready for the next service cycle? */
    00126   const Company *c = Company::Get(this->owner);
    00127   if ((c->settings.vehicle.servint_ispercent ?
    00128       (this->reliability >= Engine::Get(this->engine_type)->reliability * (100 - this->service_interval) / 100) :
    00129       (this->date_of_last_service + this->service_interval >= _date))
    00130        && !(this->type == VEH_TRAIN && HasBit(Train::From(this)->flags ,VRF_NEED_REPAIR))) {
    00131     return false;
    00132   }
    00133
    00134   /* If we're servicing anyway, because we have not disabled servicing when
    00135    * there are no breakdowns or we are playing with breakdowns, bail out. */
    00136   if (!_settings_game.order.no_servicing_if_no_breakdowns ||
    00137       _settings_game.difficulty.vehicle_breakdowns != 0) {
    00138     return true;
    00139   }
    00140
    00141   /* Test whether there is some pending autoreplace.
    00142    * Note: We do this after the service-interval test.
    00143    * There are a lot more reasons for autoreplace to fail than we can test here reasonably. */
    00144   bool pending_replace = false;
    00145   Money needed_money = c->settings.engine_renew_money;
    00146   if (needed_money > c->money) return false;
    00147
    00148   for (const Vehicle *v = this; v != NULL; v = (v->type == VEH_TRAIN) ? Train::From(v)->GetNextUnit() : NULL) {
    00149     EngineID new_engine = EngineReplacementForCompany(c, v->engine_type, v->group_id);
    00150
    00151     /* Check engine availability */
    00152     if (new_engine == INVALID_ENGINE || !HasBit(Engine::Get(new_engine)->company_avail, v->owner)) continue;
    00153
    00154     /* Check refittability */
    00155     uint32 available_cargo_types, union_mask;
    00156     GetArticulatedRefitMasks(new_engine, true, &union_mask, &available_cargo_types);
    00157     /* Is there anything to refit? */
    00158     if (union_mask != 0) {
    00159       CargoID cargo_type;
    00160       /* We cannot refit to mixed cargoes in an automated way */
    00161       if (IsArticulatedVehicleCarryingDifferentCargos(v, &cargo_type)) continue;
    00162
    00163       /* Did the old vehicle carry anything? */
    00164       if (cargo_type != CT_INVALID) {
    00165         /* We can't refit the vehicle to carry the cargo we want */
    00166         if (!HasBit(available_cargo_types, cargo_type)) continue;
    00167       }
    00168     }
    00169
    00170     /* Check money.
    00171      * We want 2*(the price of the new vehicle) without looking at the value of the vehicle we are going to sell. */
    00172     pending_replace = true;
    00173     needed_money += 2 * Engine::Get(new_engine)->GetCost();
    00174     if (needed_money > c->money) return false;
    00175   }
    00176
    00177   return pending_replace;
    00178 }
    00179
    00185 bool Vehicle::NeedsAutomaticServicing() const
    00186 {
    00187   if (_settings_game.order.gotodepot && this->HasDepotOrder()) return false;
    00188   if (this->current_order.IsType(OT_LOADING)) return false;
    00189   if (this->current_order.IsType(OT_GOTO_DEPOT) && this->current_order.GetDepotOrderType() != ODTFB_SERVICE) return false;
    00190   return NeedsServicing();
    00191 }
    00192
    00193 uint Vehicle::Crash(bool flooded)
    00194 {
    00195   assert((this->vehstatus & VS_CRASHED) == 0);
    00196   assert(this->Previous() == NULL); // IsPrimaryVehicle fails for free-wagon-chains
    00197
    00198   uint pass = 0;
    00199   /* Stop the vehicle. */
    00200   if (this->IsPrimaryVehicle()) this->vehstatus |= VS_STOPPED;
    00201   /* crash all wagons, and count passengers */
    00202   for (Vehicle *v = this; v != NULL; v = v->Next()) {
    00203     if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) pass += v->cargo.Count();
    00204     v->vehstatus |= VS_CRASHED;
    00205     MarkSingleVehicleDirty(v);
    00206   }
    00207
    00208   if (_settings_game.order.timetable_separation) this->ClearSeparation();
    00209   if (_settings_game.order.timetable_separation) ClrBit(this->vehicle_flags, VF_TIMETABLE_STARTED);
    00210
    00211   /* Dirty some windows */
    00212   InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
    00213   SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    00214   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
    00215   SetWindowDirty(WC_VEHICLE_DEPOT, this->tile);
    00216
    00217   return pass;
    00218 }
    00219
    00220 bool Vehicle::IsDrawn() const
    00221 {
    00222   return !(this->vehstatus & VS_HIDDEN) ||
    00223       (!IsTransparencySet(TO_TUNNELS) && !(_game_mode == GM_MENU) &&
    00224         ((this->type == VEH_TRAIN && Train::From(this)->track == TRACK_BIT_WORMHOLE) ||
    00225         (this->type == VEH_ROAD && RoadVehicle::From(this)->state == RVSB_WORMHOLE)));
    00226 }
    00227
    00236 void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical)
    00237 {
    00238   const Engine *e = Engine::Get(engine);
    00239   uint32 grfid = e->grf_prop.grffile->grfid;
    00240   GRFConfig *grfconfig = GetGRFConfig(grfid);
    00241
    00242   if (!HasBit(grfconfig->grf_bugs, bug_type)) {
    00243     SetBit(grfconfig->grf_bugs, bug_type);
    00244     SetDParamStr(0, grfconfig->GetName());
    00245     SetDParam(1, engine);
    00246     ShowErrorMessage(part1, part2, WL_CRITICAL);
    00247     if (!_networking) DoCommand(0, critical ? PM_PAUSED_ERROR : PM_PAUSED_NORMAL, 1, DC_EXEC, CMD_PAUSE);
    00248   }
    00249
    00250   /* debug output */
    00251   char buffer[512];
    00252
    00253   SetDParamStr(0, grfconfig->GetName());
    00254   GetString(buffer, part1, lastof(buffer));
    00255   DEBUG(grf, 0, "%s", buffer + 3);
    00256
    00257   SetDParam(1, engine);
    00258   GetString(buffer, part2, lastof(buffer));
    00259   DEBUG(grf, 0, "%s", buffer + 3);
    00260 }
    00261
    00266 Vehicle::Vehicle(VehicleType type)
    00267 {
    00268   this->type               = type;
    00269   this->coord.left         = INVALID_COORD;
    00270   this->group_id           = DEFAULT_GROUP;
    00271   this->fill_percent_te_id = INVALID_TE_ID;
    00272   this->first              = this;
    00273   this->colourmap          = PAL_NONE;
    00274 }
    00275
    00280 byte VehicleRandomBits()
    00281 {
    00282   return GB(Random(), 0, 8);
    00283 }
    00284
    00285 /* Size of the hash, 6 = 64 x 64, 7 = 128 x 128. Larger sizes will (in theory) reduce hash
    00286  * lookup times at the expense of memory usage. */
    00287 const int HASH_BITS = 7;
    00288 const int HASH_SIZE = 1 << HASH_BITS;
    00289 const int HASH_MASK = HASH_SIZE - 1;
    00290 const int TOTAL_HASH_SIZE = 1 << (HASH_BITS * 2);
    00291 const int TOTAL_HASH_MASK = TOTAL_HASH_SIZE - 1;
    00292
    00293 /* Resolution of the hash, 0 = 1*1 tile, 1 = 2*2 tiles, 2 = 4*4 tiles, etc.
    00294  * Profiling results show that 0 is fastest. */
    00295 const int HASH_RES = 0;
    00296
    00297 static Vehicle *_new_vehicle_position_hash[TOTAL_HASH_SIZE];
    00298
    00299 static Vehicle *VehicleFromHash(int xl, int yl, int xu, int yu, void *data, VehicleFromPosProc *proc, bool find_first)
    00300 {
    00301   for (int y = yl; ; y = (y + (1 << HASH_BITS)) & (HASH_MASK << HASH_BITS)) {
    00302     for (int x = xl; ; x = (x + 1) & HASH_MASK) {
    00303       Vehicle *v = _new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
    00304       for (; v != NULL; v = v->next_new_hash) {
    00305         Vehicle *a = proc(v, data);
    00306         if (find_first && a != NULL) return a;
    00307       }
    00308       if (x == xu) break;
    00309     }
    00310     if (y == yu) break;
    00311   }
    00312
    00313   return NULL;
    00314 }
    00315
    00316
    00328 static Vehicle *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc, bool find_first)
    00329 {
    00330   const int COLL_DIST = 6;
    00331
    00332   /* Hash area to scan is from xl,yl to xu,yu */
    00333   int xl = GB((x - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
    00334   int xu = GB((x + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
    00335   int yl = GB((y - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
    00336   int yu = GB((y + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
    00337
    00338   return VehicleFromHash(xl, yl, xu, yu, data, proc, find_first);
    00339 }
    00340
    00355 void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
    00356 {
    00357   VehicleFromPosXY(x, y, data, proc, false);
    00358 }
    00359
    00371 bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
    00372 {
    00373   return VehicleFromPosXY(x, y, data, proc, true) != NULL;
    00374 }
    00375
    00386 static Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc, bool find_first)
    00387 {
    00388   int x = GB(TileX(tile), HASH_RES, HASH_BITS);
    00389   int y = GB(TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS;
    00390
    00391   Vehicle *v = _new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
    00392   for (; v != NULL; v = v->next_new_hash) {
    00393     if (v->tile != tile) continue;
    00394
    00395     Vehicle *a = proc(v, data);
    00396     if (find_first && a != NULL) return a;
    00397   }
    00398
    00399   return NULL;
    00400 }
    00401
    00415 void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
    00416 {
    00417   VehicleFromPos(tile, data, proc, false);
    00418 }
    00419
    00430 bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
    00431 {
    00432   return VehicleFromPos(tile, data, proc, true) != NULL;
    00433 }
    00434
    00441 static Vehicle *EnsureNoVehicleProcZ(Vehicle *v, void *data)
    00442 {
    00443   int32 z = *(int32*)data;
    00444
    00445   if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
    00446   if (v->z_pos > z) return NULL;
    00447
    00448   return v;
    00449 }
    00450
    00456 CommandCost EnsureNoVehicleOnGround(TileIndex tile)
    00457 {
    00458   int32 z = GetTileMaxZ(tile);
    00459
    00460   /* Value v is not safe in MP games, however, it is used to generate a local
    00461    * error message only (which may be different for different machines).
    00462    * Such a message does not affect MP synchronisation.
    00463    */
    00464   Vehicle *v = VehicleFromPos(tile, &z, &EnsureNoVehicleProcZ, true);
    00465   if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
    00466   return CommandCost();
    00467 }
    00468
    00470 static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
    00471 {
    00472   if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) return NULL;
    00473   if (v == (const Vehicle *)data) return NULL;
    00474
    00475   return v;
    00476 }
    00477
    00485 CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore)
    00486 {
    00487   /* Value v is not safe in MP games, however, it is used to generate a local
    00488    * error message only (which may be different for different machines).
    00489    * Such a message does not affect MP synchronisation.
    00490    */
    00491   Vehicle *v = VehicleFromPos(tile, (void *)ignore, &GetVehicleTunnelBridgeProc, true);
    00492   if (v == NULL) v = VehicleFromPos(endtile, (void *)ignore, &GetVehicleTunnelBridgeProc, true);
    00493
    00494   if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
    00495   return CommandCost();
    00496 }
    00497
    00498 static Vehicle *EnsureNoTrainOnTrackProc(Vehicle *v, void *data)
    00499 {
    00500   TrackBits rail_bits = *(TrackBits *)data;
    00501
    00502   if (v->type != VEH_TRAIN) return NULL;
    00503
    00504   Train *t = Train::From(v);
    00505   if ((t->track != rail_bits) && !TracksOverlap(t->track | rail_bits)) return NULL;
    00506
    00507   return v;
    00508 }
    00509
    00518 CommandCost EnsureNoTrainOnTrackBits(TileIndex tile, TrackBits track_bits)
    00519 {
    00520   /* Value v is not safe in MP games, however, it is used to generate a local
    00521    * error message only (which may be different for different machines).
    00522    * Such a message does not affect MP synchronisation.
    00523    */
    00524   Vehicle *v = VehicleFromPos(tile, &track_bits, &EnsureNoTrainOnTrackProc, true);
    00525   if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
    00526   return CommandCost();
    00527 }
    00528
    00529 static void UpdateNewVehiclePosHash(Vehicle *v, bool remove)
    00530 {
    00531   Vehicle **old_hash = v->old_new_hash;
    00532   Vehicle **new_hash;
    00533
    00534   if (remove) {
    00535     new_hash = NULL;
    00536   } else {
    00537     int x = GB(TileX(v->tile), HASH_RES, HASH_BITS);
    00538     int y = GB(TileY(v->tile), HASH_RES, HASH_BITS) << HASH_BITS;
    00539     new_hash = &_new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
    00540   }
    00541
    00542   if (old_hash == new_hash) return;
    00543
    00544   /* Remove from the old position in the hash table */
    00545   if (old_hash != NULL) {
    00546     if (v->next_new_hash != NULL) v->next_new_hash->prev_new_hash = v->prev_new_hash;
    00547     *v->prev_new_hash = v->next_new_hash;
    00548   }
    00549
    00550   /* Insert vehicle at beginning of the new position in the hash table */
    00551   if (new_hash != NULL) {
    00552     v->next_new_hash = *new_hash;
    00553     if (v->next_new_hash != NULL) v->next_new_hash->prev_new_hash = &v->next_new_hash;
    00554     v->prev_new_hash = new_hash;
    00555     *new_hash = v;
    00556   }
    00557
    00558   /* Remember current hash position */
    00559   v->old_new_hash = new_hash;
    00560 }
    00561
    00562 static Vehicle *_vehicle_position_hash[0x1000];
    00563
    00564 static void UpdateVehiclePosHash(Vehicle *v, int x, int y)
    00565 {
    00566   UpdateNewVehiclePosHash(v, x == INVALID_COORD);
    00567
    00568   Vehicle **old_hash, **new_hash;
    00569   int old_x = v->coord.left;
    00570   int old_y = v->coord.top;
    00571
    00572   new_hash = (x == INVALID_COORD) ? NULL : &_vehicle_position_hash[GEN_HASH(x, y)];
    00573   old_hash = (old_x == INVALID_COORD) ? NULL : &_vehicle_position_hash[GEN_HASH(old_x, old_y)];
    00574
    00575   if (old_hash == new_hash) return;
    00576
    00577   /* remove from hash table? */
    00578   if (old_hash != NULL) {
    00579     if (v->next_hash != NULL) v->next_hash->prev_hash = v->prev_hash;
    00580     *v->prev_hash = v->next_hash;
    00581   }
    00582
    00583   /* insert into hash table? */
    00584   if (new_hash != NULL) {
    00585     v->next_hash = *new_hash;
    00586     if (v->next_hash != NULL) v->next_hash->prev_hash = &v->next_hash;
    00587     v->prev_hash = new_hash;
    00588     *new_hash = v;
    00589   }
    00590 }
    00591
    00592 void ResetVehiclePosHash()
    00593 {
    00594   Vehicle *v;
    00595   FOR_ALL_VEHICLES(v) { v->old_new_hash = NULL; }
    00596   memset(_vehicle_position_hash, 0, sizeof(_vehicle_position_hash));
    00597   memset(_new_vehicle_position_hash, 0, sizeof(_new_vehicle_position_hash));
    00598 }
    00599
    00600 void ResetVehicleColourMap()
    00601 {
    00602   Vehicle *v;
    00603   FOR_ALL_VEHICLES(v) { v->colourmap = PAL_NONE; }
    00604 }
    00605
    00610 typedef SmallMap<Vehicle *, bool, 4> AutoreplaceMap;
    00611 static AutoreplaceMap _vehicles_to_autoreplace;
    00612
    00613 void InitializeVehicles()
    00614 {
    00615   _age_cargo_skip_counter = 1;
    00616
    00617   _vehicles_to_autoreplace.Reset();
    00618   ResetVehiclePosHash();
    00619 }
    00620
    00621 uint CountVehiclesInChain(const Vehicle *v)
    00622 {
    00623   uint count = 0;
    00624   do count++; while ((v = v->Next()) != NULL);
    00625   return count;
    00626 }
    00627
    00633 void CountCompanyVehicles(CompanyID cid, uint counts[4])
    00634 {
    00635   for (uint i = 0; i < 4; i++) counts[i] = 0;
    00636
    00637   const Vehicle *v;
    00638   FOR_ALL_VEHICLES(v) {
    00639     if (v->owner == cid && v->IsPrimaryVehicle()) counts[v->type]++;
    00640   }
    00641 }
    00642
    00647 bool Vehicle::IsEngineCountable() const
    00648 {
    00649   switch (this->type) {
    00650     case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft(); // don't count plane shadows and helicopter rotors
    00651     case VEH_TRAIN:
    00652       return !this->IsArticulatedPart() && // tenders and other articulated parts
    00653           !Train::From(this)->IsRearDualheaded(); // rear parts of multiheaded engines
    00654     case VEH_ROAD: return RoadVehicle::From(this)->IsFrontEngine();
    00655     case VEH_SHIP: return true;
    00656     default: return false; // Only count company buildable vehicles
    00657   }
    00658 }
    00659
    00667 void Vehicle::HandlePathfindingResult(bool path_found)
    00668 {
    00669   if (path_found) {
    00670     /* Route found, is the vehicle marked with "lost" flag? */
    00671     if (!HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;
    00672
    00673     /* Clear the flag as the PF's problem was solved. */
    00674     ClrBit(this->vehicle_flags, VF_PATHFINDER_LOST);
    00675     /* Delete the news item. */
    00676     DeleteVehicleNews(this->index, STR_NEWS_VEHICLE_IS_LOST);
    00677     return;
    00678   }
    00679
    00680   /* Were we already lost? */
    00681   if (HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;
    00682
    00683   /* It is first time the problem occurred, set the "lost" flag. */
    00684   SetBit(this->vehicle_flags, VF_PATHFINDER_LOST);
    00685   /* Notify user about the event. */
    00686   AI::NewEvent(this->owner, new AIEventVehicleLost(this->index));
    00687   if (_settings_client.gui.lost_vehicle_warn && this->owner == _local_company) {
    00688     SetDParam(0, this->index);
    00689     AddVehicleNewsItem(STR_NEWS_VEHICLE_IS_LOST, NS_ADVICE, this->index);
    00690   }
    00691 }
    00692
    00694 void Vehicle::PreDestructor()
    00695 {
    00696   if (CleaningPool()) return;
    00697
    00698   if (Station::IsValidID(this->last_station_visited)) {
    00699     Station *st = Station::Get(this->last_station_visited);
    00700     st->loading_vehicles.remove(this);
    00701
    00702     HideFillingPercent(&this->fill_percent_te_id);
    00703     this->CancelReservation(INVALID_STATION, st);
    00704     delete this->cargo_payment;
    00705   }
    00706
    00707   if (this->IsEngineCountable()) {
    00708     Company::Get(this->owner)->num_engines[this->engine_type]--;
    00709     if (this->owner == _local_company) InvalidateAutoreplaceWindow(this->engine_type, this->group_id);
    00710
    00711     DeleteGroupHighlightOfVehicle(this);
    00712     if (Group::IsValidID(this->group_id)) Group::Get(this->group_id)->num_engines[this->engine_type]--;
    00713     if (this->IsPrimaryVehicle()) DecreaseGroupNumVehicle(this->group_id);
    00714   }
    00715
    00716   if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) {
    00717     Aircraft *a = Aircraft::From(this);
    00718     Station *st = GetTargetAirportIfValid(a);
    00719     if (st != NULL) {
    00720       const AirportFTA *layout = st->airport.GetFTA()->layout;
    00721       CLRBITS(st->airport.flags, layout[a->previous_pos].block | layout[a->pos].block);
    00722     }
    00723   }
    00724
    00725
    00726   if (this->type == VEH_ROAD && this->IsPrimaryVehicle()) {
    00727     RoadVehicle *v = RoadVehicle::From(this);
    00728     if (!(v->vehstatus & VS_CRASHED) && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
    00729       /* Leave the drive through roadstop, when you have not already left it. */
    00730       RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
    00731     }
    00732   }
    00733
    00734   if (this->Previous() == NULL) {
    00735     InvalidateWindowData(WC_VEHICLE_DEPOT, this->tile);
    00736   }
    00737
    00738   if (this->IsPrimaryVehicle()) {
    00739     DeleteWindowById(WC_VEHICLE_VIEW, this->index);
    00740     DeleteWindowById(WC_VEHICLE_ORDERS, this->index);
    00741     DeleteWindowById(WC_VEHICLE_REFIT, this->index);
    00742     DeleteWindowById(WC_VEHICLE_DETAILS, this->index);
    00743     DeleteWindowById(WC_VEHICLE_TIMETABLE, this->index);
    00744     SetWindowDirty(WC_COMPANY, this->owner);
    00745     OrderBackup::ClearVehicle(this);
    00746   }
    00747   InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
    00748
    00749   this->cargo.Truncate(0);
    00750   DeleteVehicleOrders(this);
    00751   DeleteDepotHighlightOfVehicle(this);
    00752
    00753   extern void StopGlobalFollowVehicle(const Vehicle *v);
    00754   StopGlobalFollowVehicle(this);
    00755
    00756   ReleaseDisastersTargetingVehicle(this->index);
    00757 }
    00758
    00759 Vehicle::~Vehicle()
    00760 {
    00761   free(this->name);
    00762
    00763   if (CleaningPool()) {
    00764     this->cargo.OnCleanPool();
    00765     return;
    00766   }
    00767
    00768   /* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles,
    00769    * it may happen that vehicle chain is deleted when visible */
    00770   if (this->IsDrawn()) MarkSingleVehicleDirty(this);
    00771
    00772   Vehicle *v = this->Next();
    00773   this->SetNext(NULL);
    00774
    00775   delete v;
    00776
    00777   UpdateVehiclePosHash(this, INVALID_COORD, 0);
    00778   DeleteVehicleNews(this->index, INVALID_STRING_ID);
    00779   DeleteNewGRFInspectWindow(GetGrfSpecFeature(this->type), this->index);
    00780 }
    00781
    00786 void VehicleEnteredDepotThisTick(Vehicle *v)
    00787 {
    00788   /* Vehicle should stop in the depot if it was in 'stopping' state */
    00789   _vehicles_to_autoreplace[v] = !(v->vehstatus & VS_STOPPED);
    00790
    00791   /* We ALWAYS set the stopped state. Even when the vehicle does not plan on
    00792    * stopping in the depot, so we stop it to ensure that it will not reserve
    00793    * the path out of the depot before we might autoreplace it to a different
    00794    * engine. The new engine would not own the reserved path we store that we
    00795    * stopped the vehicle, so autoreplace can start it again */
    00796   v->vehstatus |= VS_STOPPED;
    00797 }
    00798
    00804 static void RunVehicleDayProc()
    00805 {
    00806   if (_game_mode != GM_NORMAL) return;
    00807
    00808   /* Run the day_proc for every DAY_TICKS vehicle starting at _date_fract. */
    00809   for (size_t i = _date_fract; i < Vehicle::GetPoolSize(); i += DAY_TICKS) {
    00810     Vehicle *v = Vehicle::Get(i);
    00811     if (v == NULL) continue;
    00812
    00813     /* Call the 32-day callback if needed */
    00814     if ((v->day_counter & 0x1F) == 0) {
    00815       uint16 callback = GetVehicleCallback(CBID_VEHICLE_32DAY_CALLBACK, 0, 0, v->engine_type, v);
    00816       if (callback != CALLBACK_FAILED) {
    00817         if (HasBit(callback, 0)) TriggerVehicle(v, VEHICLE_TRIGGER_CALLBACK_32); // Trigger vehicle trigger 10
    00818         if (HasBit(callback, 1)) v->colourmap = PAL_NONE;
    00819       }
    00820     }
    00821
    00822     /* This is called once per day for each vehicle, but not in the first tick of the day */
    00823     v->OnNewDay();
    00824   }
    00825 }
    00826
    00827 void CallVehicleTicks()
    00828 {
    00829   _vehicles_to_autoreplace.Clear();
    00830
    00831   _age_cargo_skip_counter = (_age_cargo_skip_counter == 0) ? CARGO_AGING_TICKS - 1 : (_age_cargo_skip_counter - 1);
    00832
    00833   RunVehicleDayProc();
    00834
    00835   Station *st;
    00836   FOR_ALL_STATIONS(st) LoadUnloadStation(st);
    00837
    00838   Vehicle *v;
    00839   FOR_ALL_VEHICLES(v) {
    00840     /* Vehicle could be deleted in this tick */
    00841     if (!v->Tick()) {
    00842       assert(Vehicle::Get(vehicle_index) == NULL);
    00843       continue;
    00844     }
    00845
    00846     assert(Vehicle::Get(vehicle_index) == v);
    00847
    00848     switch (v->type) {
    00849       default: break;
    00850
    00851       case VEH_TRAIN:
    00852         if (HasBit(Train::From(v)->flags, VRF_TO_HEAVY)) {
    00853           _current_company = v->owner;
    00854           if (IsLocalCompany()) {
    00855             SetDParam(0, v->index);
    00856             SetDParam(1, STR_ERROR_TRAIN_TOO_HEAVY);
    00857             AddVehicleNewsItem(STR_ERROR_TRAIN_TOO_HEAVY, NS_ADVICE, v->index);
    00858             ClrBit(Train::From(v)->flags,VRF_TO_HEAVY);
    00859           }
    00860           _current_company = OWNER_NONE;
    00861         }
    00862       case VEH_ROAD:
    00863       case VEH_AIRCRAFT:
    00864       case VEH_SHIP:
    00865         if (_age_cargo_skip_counter == 0) v->cargo.AgeCargo();
    00866
    00867         if (v->type == VEH_TRAIN && Train::From(v)->IsWagon()) continue;
    00868         if (v->type == VEH_AIRCRAFT && v->subtype != AIR_HELICOPTER) continue;
    00869         if (v->type == VEH_ROAD && !RoadVehicle::From(v)->IsFrontEngine()) continue;
    00870
    00871         v->motion_counter += v->cur_speed;
    00872         /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
    00873         if (GB(v->motion_counter, 0, 8) < v->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
    00874
    00875         /* Play an alterate running sound every 16 ticks */
    00876         if (GB(v->tick_counter, 0, 4) == 0) PlayVehicleSound(v, v->cur_speed > 0 ? VSE_RUNNING_16 : VSE_STOPPED_16);
    00877     }
    00878   }
    00879
    00880   Backup<CompanyByte> cur_company(_current_company, FILE_LINE);
    00881   for (AutoreplaceMap::iterator it = _vehicles_to_autoreplace.Begin(); it != _vehicles_to_autoreplace.End(); it++) {
    00882     v = it->first;
    00883     /* Autoreplace needs the current company set as the vehicle owner */
    00884     cur_company.Change(v->owner);
    00885
    00886     /* Start vehicle if we stopped them in VehicleEnteredDepotThisTick()
    00887      * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that
    00888      * they are already leaving the depot again before being replaced. */
    00889     if (it->second) v->vehstatus &= ~VS_STOPPED;
    00890
    00891     /* Store the position of the effect as the vehicle pointer will become invalid later */
    00892     int x = v->x_pos;
    00893     int y = v->y_pos;
    00894     int z = v->z_pos;
    00895
    00896     const Company *c = Company::Get(_current_company);
    00897     SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, (Money)c->settings.engine_renew_money));
    00898     CommandCost res = DoCommand(0, v->index, 0, DC_EXEC, CMD_AUTOREPLACE_VEHICLE);
    00899     SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, -(Money)c->settings.engine_renew_money));
    00900
    00901     if (!IsLocalCompany()) continue;
    00902
    00903     if (res.Succeeded()) {
    00904       ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
    00905       continue;
    00906     }
    00907
    00908     StringID error_message = res.GetErrorMessage();
    00909     if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message == INVALID_STRING_ID) continue;
    00910
    00911     if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT;
    00912
    00913     StringID message;
    00914     if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
    00915       message = error_message;
    00916     } else {
    00917       message = STR_NEWS_VEHICLE_AUTORENEW_FAILED;
    00918     }
    00919
    00920     SetDParam(0, v->index);
    00921     SetDParam(1, error_message);
    00922     AddVehicleNewsItem(message, NS_ADVICE, v->index);
    00923   }
    00924
    00925   cur_company.Restore();
    00926 }
    00927
    00932 static void DoDrawVehicle(const Vehicle *v)
    00933 {
    00934   SpriteID image = v->cur_image;
    00935   PaletteID pal = PAL_NONE;
    00936
    00937   if (v->vehstatus & VS_DEFPAL) pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
    00938
    00939   /* Check whether the vehicle shall be transparent due to the game state */
    00940   bool shadowed = (v->vehstatus & (VS_SHADOW | VS_HIDDEN));
    00941
    00942   if (v->type == VEH_EFFECT) {
    00943     /* Check whether the vehicle shall be transparent/invisible due to GUI settings.
    00944      * However, transparent smoke and bubbles look weird, so always hide them. */
    00945     TransparencyOption to = EffectVehicle::From(v)->GetTransparencyOption();
    00946     if (to != TO_INVALID && (IsTransparencySet(to) || IsInvisibilitySet(to))) return;
    00947   }
    00948
    00949   AddSortableSpriteToDraw(image, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
    00950     v->x_extent, v->y_extent, v->z_extent, v->z_pos, shadowed);
    00951 }
    00952
    00957 void ViewportAddVehicles(DrawPixelInfo *dpi)
    00958 {
    00959   /* The bounding rectangle */
    00960   const int l = dpi->left;
    00961   const int r = dpi->left + dpi->width;
    00962   const int t = dpi->top;
    00963   const int b = dpi->top + dpi->height;
    00964
    00965   /* The hash area to scan */
    00966   int xl, xu, yl, yu;
    00967
    00968   if (dpi->width + 70 < (1 << (7 + 6))) {
    00969     xl = GB(l - 70, 7, 6);
    00970     xu = GB(r,      7, 6);
    00971   } else {
    00972     /* scan whole hash row */
    00973     xl = 0;
    00974     xu = 0x3F;
    00975   }
    00976
    00977   if (dpi->height + 70 < (1 << (6 + 6))) {
    00978     yl = GB(t - 70, 6, 6) << 6;
    00979     yu = GB(b,      6, 6) << 6;
    00980   } else {
    00981     /* scan whole column */
    00982     yl = 0;
    00983     yu = 0x3F << 6;
    00984   }
    00985
    00986   for (int y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
    00987     for (int x = xl;; x = (x + 1) & 0x3F) {
    00988       const Vehicle *v = _vehicle_position_hash[x + y]; // already masked & 0xFFF
    00989
    00990       while (v != NULL) {
    00991         if (v->IsDrawn() &&
    00992             l <= v->coord.right &&
    00993             t <= v->coord.bottom &&
    00994             r >= v->coord.left &&
    00995             b >= v->coord.top) {
    00996           DoDrawVehicle(v);
    00997         }
    00998         v = v->next_hash;
    00999       }
    01000
    01001       if (x == xu) break;
    01002     }
    01003
    01004     if (y == yu) break;
    01005   }
    01006 }
    01007
    01015 Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y)
    01016 {
    01017   Vehicle *found = NULL, *v;
    01018   uint dist, best_dist = UINT_MAX;
    01019
    01020   if ((uint)(x -= vp->left) >= (uint)vp->width || (uint)(y -= vp->top) >= (uint)vp->height) return NULL;
    01021
    01022   x = ScaleByZoom(x, vp->zoom) + vp->virtual_left;
    01023   y = ScaleByZoom(y, vp->zoom) + vp->virtual_top;
    01024
    01025   FOR_ALL_VEHICLES(v) {
    01026     if (v->IsDrawn() && !(v->vehstatus & VS_UNCLICKABLE) &&
    01027         x >= v->coord.left && x <= v->coord.right &&
    01028         y >= v->coord.top && y <= v->coord.bottom) {
    01029
    01030       dist = max(
    01031         abs(((v->coord.left + v->coord.right) >> 1) - x),
    01032         abs(((v->coord.top + v->coord.bottom) >> 1) - y)
    01033       );
    01034
    01035       if (dist < best_dist) {
    01036         found = v;
    01037         best_dist = dist;
    01038       }
    01039     }
    01040   }
    01041
    01042   return found;
    01043 }
    01044
    01049 void DecreaseVehicleValue(Vehicle *v)
    01050 {
    01051   v->value -= v->value >> 8;
    01052   SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    01053 }
    01054
    01059 static const byte _breakdown_chances[4][4] = {
    01060   { //Trains:
    01061     25,
    01062     51,
    01063     127,
    01064     255,
    01065   },
    01066   { //Road Vehicles:
    01067     51,
    01068     76,
    01069     153,
    01070     255,
    01071   },
    01072   { //Ships:
    01073     51,
    01074     76,
    01075     178,
    01076     255,
    01077   },
    01078   { //Aircraft:
    01079     178,
    01080     229,
    01081     255,
    01082     255,
    01083   },
    01084 };
    01085
    01092 void
    01093 DetermineBreakdownType( Vehicle *v, uint32 r ) {
    01094   /* If 'improved breakdowns' is off, just do the classic breakdown. */
    01095   if ( !_settings_game.vehicle.improved_breakdowns) {
    01096     v->breakdown_type = BREAKDOWN_CRITICAL;
    01097     v->breakdown_severity = 40; // Only used by aircraft (321 km/h).
    01098     return;
    01099   }
    01100
    01101   byte rand = GB(r, 8, 8);
    01102   const byte *breakdown_type_chance = _breakdown_chances[v->type];
    01103
    01104   if (v->type == VEH_AIRCRAFT) {
    01105     if (rand <= breakdown_type_chance[BREAKDOWN_AIRCRAFT_SPEED]) {
    01106       v->breakdown_type = BREAKDOWN_AIRCRAFT_SPEED;
    01107       /* All speed values here are 1/8th of the real max speed in km/h. */
    01108       byte max_speed = min(AircraftVehInfo(v->engine_type)->max_speed >> 3, 255);
    01109       byte min_speed = min(15 + (max_speed >> 2), AircraftVehInfo( v->engine_type)->max_speed >> 4);
    01110       v->breakdown_severity = min_speed + (((v->reliability + GB(r, 16, 16)) * (max_speed - min_speed)) >> 17);
    01111     } else if (rand <= breakdown_type_chance[BREAKDOWN_AIRCRAFT_DEPOT]) {
    01112       v->breakdown_type = BREAKDOWN_AIRCRAFT_DEPOT;
    01113     } else if (rand <= breakdown_type_chance[BREAKDOWN_AIRCRAFT_EM_LANDING]) {
    01114       /* Emergency landings only happen when reliability < 87%. */
    01115       if (v->reliability < 0xDDDD) {
    01116         v->breakdown_type = BREAKDOWN_AIRCRAFT_EM_LANDING;
    01117       } else {
    01118         /* Try again. */
    01119         DetermineBreakdownType(v, Random());
    01120       }
    01121     } else {
    01122       NOT_REACHED();
    01123     }
    01124     return;
    01125   }
    01126
    01127   if (rand <= breakdown_type_chance[BREAKDOWN_CRITICAL]) {
    01128     v->breakdown_type = BREAKDOWN_CRITICAL;
    01129   } else if (rand <= breakdown_type_chance[BREAKDOWN_EM_STOP]) {
    01130     /* Non-front engines cannot have emergency stops. */
    01131     if (v->type == VEH_TRAIN && !(Train::From(v)->IsFrontEngine())) {
    01132       return DetermineBreakdownType(v, Random());
    01133     }
    01134     v->breakdown_type = BREAKDOWN_EM_STOP;
    01135     v->breakdown_delay >>= 2; // Emergency stops don't last long (1/4 of normal).
    01136   } else if (rand <= breakdown_type_chance[BREAKDOWN_LOW_SPEED]) {
    01137     v->breakdown_type = BREAKDOWN_LOW_SPEED;
    01138     /* Average of random and reliability. */
    01139     uint16 rand2 = (GB(r, 16, 16) + v->reliability) >> 1;
    01140     uint16 max_speed =
    01141         (v->type == VEH_TRAIN) ? GetVehicleProperty(v, PROP_TRAIN_SPEED, RailVehInfo(v->engine_type)->max_speed) :
    01142         (v->type == VEH_ROAD) ? GetVehicleProperty(v, PROP_ROADVEH_SPEED, RoadVehInfo(v->engine_type)->max_speed) :
    01143         (v->type == VEH_SHIP) ? GetVehicleProperty(v,PROP_SHIP_SPEED, ShipVehInfo(v->engine_type)->max_speed) :
    01144         GetVehicleProperty(v, PROP_AIRCRAFT_SPEED, AircraftVehInfo(v->engine_type)->max_speed);
    01145     byte min_speed = min(41, max_speed >> 2);
    01146     /* We use the min() function here because we want to use the real value of max_speed for the min_speed calculation. */
    01147     max_speed = min(max_speed, 255);
    01148     v->breakdown_severity = Clamp((max_speed * rand2) >> 16, min_speed, max_speed);
    01149   } else if (rand <= breakdown_type_chance[BREAKDOWN_LOW_POWER]) {
    01150     v->breakdown_type = BREAKDOWN_LOW_POWER;
    01153     if (GB(r, 7, 1)) {
    01154       v->breakdown_severity = Clamp((GB(r, 16, 16) + v->reliability) >> 9, 26, 231);
    01155     } else {
    01156       v->breakdown_severity = 0;
    01157     }
    01158   } else {
    01159     NOT_REACHED();
    01160   }
    01161 }
    01162
    01163 void CheckVehicleBreakdown(Vehicle *v)
    01164 {
    01165   int rel, rel_old;
    01166
    01167   /* decrease reliability */
    01168   v->reliability = rel = max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
    01169   if ((rel_old >> 8) != (rel >> 8)) SetWindowDirty(WC_VEHICLE_DETAILS, v->First()->index);
    01170
    01171   if (v->breakdown_ctr != 0 || (v->First()->vehstatus & VS_STOPPED) ||
    01172       _settings_game.difficulty.vehicle_breakdowns < 1 ||
    01173       v->First()->cur_speed < 5 || _game_mode == GM_MENU ||
    01174       (v->type == VEH_AIRCRAFT && ((Aircraft*)v)->state != FLYING) ||
    01175       (v->type == VEH_TRAIN && !(Train::From(v)->IsFrontEngine()) && !_settings_game.vehicle.improved_breakdowns)) {
    01176     return;
    01177   }
    01178
    01179   uint32 r1 = Random();
    01180   uint32 r2 = Random();
    01181
    01182   byte chance = 128;
    01183   if (_settings_game.vehicle.improved_breakdowns) {
    01184     /* Dual engines have their breakdown chances reduced to 70% of the normal value */
    01185     chance = (v->type == VEH_TRAIN && Train::From(v)->IsMultiheaded()) ? v->First()->breakdown_chance * 7 / 10 : v->First()->breakdown_chance;
    01186   } else if (v->type == VEH_SHIP) {
    01187     chance = 64;
    01188   }
    01189
    01198   if ((uint32) (0xffff - v->reliability) * _settings_game.difficulty.vehicle_breakdowns * chance > GB(r1, 0, 24) * 10) {
    01199     v->breakdown_ctr = GB(r1, 24, 6) + 0xF;
    01200     v->breakdown_delay = GB(r2, 0, 7) + 0x80;
    01201     DetermineBreakdownType(v, r2);
    01202   }
    01203 }
    01204
    01211 bool Vehicle::HandleBreakdown()
    01212 {
    01213   /* Possible states for Vehicle::breakdown_ctr
    01214    * 0  - vehicle is running normally
    01215    * 1  - vehicle is currently broken down
    01216    * 2  - vehicle is going to break down now
    01217    * >2 - vehicle is counting down to the actual breakdown event */
    01218   switch (this->breakdown_ctr) {
    01219     case 0:
    01220       return false;
    01221
    01222     case 2:
    01223       this->breakdown_ctr = 1;
    01224
    01225       if (this->breakdowns_since_last_service != 255) {
    01226         this->breakdowns_since_last_service++;
    01227       }
    01228
    01229       SetWindowDirty(WC_VEHICLE_VIEW, this->index);
    01230       SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
    01231
    01232       if (this->type == VEH_AIRCRAFT) {
    01233         this->MarkDirty();
    01234         assert(this->breakdown_type <= BREAKDOWN_AIRCRAFT_EM_LANDING);
    01235         /* Aircraft just need this flag, the rest is handled elsewhere */
    01236         this->vehstatus |= VS_AIRCRAFT_BROKEN;
    01237         if(this->breakdown_type == BREAKDOWN_AIRCRAFT_SPEED ||
    01238             (this->current_order.IsType(OT_GOTO_DEPOT) &&
    01239             (this->current_order.GetDepotOrderType() & ODTFB_BREAKDOWN) &&
    01240             GetTargetAirportIfValid(Aircraft::From(this)) != NULL)) {
    01241           return false;
    01242         }
    01243         FindBreakdownDestination(Aircraft::From(this));
    01244       } else if (this->type == VEH_TRAIN) {
    01245         if (this->breakdown_type == BREAKDOWN_LOW_POWER ||
    01246             this->First()->cur_speed <= ((this->breakdown_type == BREAKDOWN_LOW_SPEED) ? this->breakdown_severity : 0)) {
    01247           switch ( this->breakdown_type ) {
    01248             case BREAKDOWN_CRITICAL:
    01249
    01250               if (!PlayVehicleSound(this, VSE_BREAKDOWN)) {
    01251                 SndPlayVehicleFx((_settings_game.game_creation.landscape != LT_TOYLAND) ?
    01252                 (this->type == VEH_TRAIN ? SND_10_TRAIN_BREAKDOWN : SND_0F_VEHICLE_BREAKDOWN) :
    01253                 (this->type == VEH_TRAIN ? SND_3A_COMEDY_BREAKDOWN_2 : SND_35_COMEDY_BREAKDOWN), this);
    01254               }
    01255
    01256               if (!(this->vehstatus & VS_HIDDEN)) {
    01257                 EffectVehicle *u = CreateEffectVehicleRel(this, 4, 4, 5, EV_BREAKDOWN_SMOKE);
    01258                 if (u != NULL) u->animation_state = this->breakdown_delay * 2;
    01259               }
    01260
    01261               /* Max Speed reduction*/
    01262               if (_settings_game.vehicle.improved_breakdowns) {
    01263                 if (!HasBit(Train::From(this)->flags,VRF_NEED_REPAIR)) {
    01264                   const Engine *e = Engine::Get(this->engine_type);
    01265                   const RailVehicleInfo *rvi = &e->u.rail;
    01266                   if (rvi->max_speed > this->vcache.cached_max_speed) this->vcache.cached_max_speed = rvi->max_speed;
    01267                 }
    01268
    01269                 this->vcache.cached_max_speed =
    01270                     min(
    01271                     this->vcache.cached_max_speed - (this->vcache.cached_max_speed >> 1) / Train::From(this->First())->tcache.cached_num_engines + 1,
    01272                     this->vcache.cached_max_speed);
    01273                 SetBit(Train::From(this)->flags, VRF_NEED_REPAIR);
    01274                 Train::From(this->First())->ConsistChanged(true);
    01275               }
    01276             /* FALL THROUGH */
    01277
    01278             case BREAKDOWN_EM_STOP:
    01279               CheckBreakdownFlags(Train::From(this->First()));
    01280               SetBit(Train::From(this->First())->flags, VRF_BREAKDOWN_STOPPED);
    01281               break;
    01282
    01283             case BREAKDOWN_LOW_SPEED:
    01284               CheckBreakdownFlags(Train::From(this->First()));
    01285               SetBit(Train::From(this->First())->flags, VRF_BREAKDOWN_SPEED);
    01286               break;
    01287
    01288             case BREAKDOWN_LOW_POWER:
    01289               SetBit(Train::From(this->First())->flags, VRF_BREAKDOWN_POWER);
    01290               break;
    01291             default: NOT_REACHED();
    01292           }
    01293
    01294           this->First()->MarkDirty();
    01295           SetWindowDirty(WC_VEHICLE_VIEW, this->First()->index);
    01296           SetWindowDirty(WC_VEHICLE_DETAILS, this->First()->index);
    01297         } else {
    01298           this->breakdown_ctr = 2; // Wait until slowdown.
    01299           this->breakdowns_since_last_service--;
    01300           SetBit(Train::From(this)->flags, VRF_BREAKDOWN_BRAKING);
    01301           return false;
    01302         }
    01303
    01304         if ((!(this->vehstatus & VS_HIDDEN)) && ((this->breakdown_type == BREAKDOWN_LOW_SPEED || this->breakdown_type == BREAKDOWN_LOW_POWER) && (this->tick_counter & 0x1F) == 0)) {
    01305           CreateEffectVehicleRel(this, 0, 0, 2, EV_CRASH_SMOKE); // Some grey clouds to indicate a broken engine.
    01306         }
    01307       } else {
    01308         switch (this->breakdown_type) {
    01309           case BREAKDOWN_CRITICAL:
    01310             if (!PlayVehicleSound( this, VSE_BREAKDOWN)) {
    01311               SndPlayVehicleFx((_settings_game.game_creation.landscape != LT_TOYLAND) ? SND_0F_VEHICLE_BREAKDOWN : SND_35_COMEDY_BREAKDOWN, this);
    01312             }
    01313
    01314             if (!(this->vehstatus & VS_HIDDEN)) {
    01315               EffectVehicle *u = CreateEffectVehicleRel(this, 4, 4, 5, EV_BREAKDOWN_SMOKE);
    01316               if (u != NULL) u->animation_state = this->breakdown_delay * 2;
    01317             }
    01318             /* FALL THROUGH */
    01319
    01320           case BREAKDOWN_EM_STOP:
    01321             this->cur_speed = 0;
    01322             break;
    01323
    01324           case BREAKDOWN_LOW_SPEED:
    01325           case BREAKDOWN_LOW_POWER:
    01326             /* Do nothing. */
    01327             break;
    01328           default: NOT_REACHED();
    01329       }
    01330         if ((!(this->vehstatus & VS_HIDDEN)) &&
    01331             (( this->breakdown_type == BREAKDOWN_LOW_SPEED || this->breakdown_type == BREAKDOWN_LOW_POWER) &&
    01332             (this->tick_counter & 0x1F) == 0)) {
    01333           /* Some gray clouds to indicate a broken RV. */
    01334           CreateEffectVehicleRel(this, 0, 0, 2, EV_CRASH_SMOKE);
    01335         }
    01336
    01337         return (this->breakdown_type == BREAKDOWN_CRITICAL || this->breakdown_type == BREAKDOWN_EM_STOP);
    01338       }
    01339       /* FALL THROUGH */
    01340     case 1:
    01341       /* Aircraft breakdowns end only when arriving at the airport */
    01342       if (this->type == VEH_AIRCRAFT) return false;
    01343
    01344       /* For trains this function is called twice per tick, so decrease v->breakdown_delay at half the rate */
    01345       if ((this->tick_counter & (this->type == VEH_TRAIN ? 3 : 1)) == 0) {
    01346         if (--this->breakdown_delay == 0) {
    01347           this->breakdown_ctr = 0;
    01348           if(this->type == VEH_TRAIN) {
    01349             CheckBreakdownFlags(Train::From(this->First()));
    01350             this->First()->MarkDirty();
    01351             SetWindowDirty(WC_VEHICLE_VIEW, this->First()->index);
    01352           } else {
    01353             this->MarkDirty();
    01354             SetWindowDirty(WC_VEHICLE_VIEW, this->index);
    01355           }
    01356         }
    01357       }
    01358       return (this->breakdown_type == BREAKDOWN_CRITICAL || this->breakdown_type == BREAKDOWN_EM_STOP);
    01359
    01360     default:
    01361       if (!this->current_order.IsType(OT_LOADING)) this->breakdown_ctr--;
    01362       return false;
    01363   }
    01364 }
    01365
    01370 void AgeVehicle(Vehicle *v)
    01371 {
    01372   if (v->age < MAX_DAY) v->age++;
    01373
    01374   int age = v->age - v->max_age;
    01375   if (age == DAYS_IN_LEAP_YEAR * 0 || age == DAYS_IN_LEAP_YEAR * 1 ||
    01376       age == DAYS_IN_LEAP_YEAR * 2 || age == DAYS_IN_LEAP_YEAR * 3 || age == DAYS_IN_LEAP_YEAR * 4) {
    01377     v->reliability_spd_dec <<= 1;
    01378   }
    01379
    01380   SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    01381
    01382   /* Don't warn about non-primary or not ours vehicles or vehicles that are crashed */
    01383   if (v->Previous() != NULL || v->owner != _local_company || (v->vehstatus & VS_CRASHED) != 0) return;
    01384
    01385   /* Don't warn if a renew is active */
    01386   if (Company::Get(v->owner)->settings.engine_renew && Engine::Get(v->engine_type)->company_avail != 0) return;
    01387
    01388   StringID str;
    01389   if (age == -DAYS_IN_LEAP_YEAR) {
    01390     str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
    01391   } else if (age == 0) {
    01392     str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
    01393   } else if (age > 0 && (age % DAYS_IN_LEAP_YEAR) == 0) {
    01394     str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
    01395   } else {
    01396     return;
    01397   }
    01398
    01399   SetDParam(0, v->index);
    01400   AddVehicleNewsItem(str, NS_ADVICE, v->index);
    01401 }
    01402
    01409 uint8 CalcPercentVehicleFilled(const Vehicle *v, StringID *colour)
    01410 {
    01411   int count = 0;
    01412   int max = 0;
    01413   int cars = 0;
    01414   int unloading = 0;
    01415   bool loading = false;
    01416
    01417   const Vehicle *u = v;
    01418   /* The station may be NULL when the (colour) string does not need to be set. */
    01419   const Station *st = Station::GetIfValid(v->last_station_visited);
    01420   assert(colour == NULL || st != NULL);
    01421
    01422   /* Count up max and used */
    01423   for (; v != NULL; v = v->Next()) {
    01424     count += v->cargo.OnboardCount();
    01425     max += v->cargo_cap;
    01426     if (v->cargo_cap != 0 && colour != NULL) {
    01427       unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0;
    01428       loading |= !(u->current_order.GetLoadType() & OLFB_NO_LOAD) && st->goods[v->cargo_type].days_since_pickup != 255;
    01429       cars++;
    01430     }
    01431   }
    01432
    01433   if (colour != NULL) {
    01434     if (unloading == 0 && loading) {
    01435       *colour = STR_PERCENT_UP;
    01436     } else if (cars == unloading || !loading) {
    01437       *colour = STR_PERCENT_DOWN;
    01438     } else {
    01439       *colour = STR_PERCENT_UP_DOWN;
    01440     }
    01441   }
    01442
    01443   /* Train without capacity */
    01444   if (max == 0) return 100;
    01445
    01446   /* Return the percentage */
    01447   return (count * 100) / max;
    01448 }
    01449
    01454 void VehicleEnterDepot(Vehicle *v)
    01455 {
    01456   /* Always work with the front of the vehicle */
    01457   assert(v == v->First());
    01458
    01459   switch (v->type) {
    01460     case VEH_TRAIN: {
    01461       Train *t = Train::From(v);
    01462       SetWindowClassesDirty(WC_TRAINS_LIST);
    01463       /* Clear path reservation */
    01464       SetDepotReservation(t->tile, false);
    01465       if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(t->tile);
    01466
    01467       UpdateSignalsOnSegment(t->tile, INVALID_DIAGDIR, t->owner);
    01468       t->wait_counter = 0;
    01469       t->force_proceed = TFP_NONE;
    01470       ClrBit(t->flags, VRF_TOGGLE_REVERSE);
    01471       t->ConsistChanged(true);
    01472       break;
    01473     }
    01474
    01475     case VEH_ROAD:
    01476       SetWindowClassesDirty(WC_ROADVEH_LIST);
    01477       break;
    01478
    01479     case VEH_SHIP: {
    01480       SetWindowClassesDirty(WC_SHIPS_LIST);
    01481       Ship *ship = Ship::From(v);
    01482       ship->state = TRACK_BIT_DEPOT;
    01483       ship->UpdateCache();
    01484       ship->UpdateViewport(true, true);
    01485       SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
    01486       break;
    01487     }
    01488
    01489     case VEH_AIRCRAFT:
    01490       SetWindowClassesDirty(WC_AIRCRAFT_LIST);
    01491       HandleAircraftEnterHangar(Aircraft::From(v));
    01492       break;
    01493     default: NOT_REACHED();
    01494   }
    01495   SetWindowDirty(WC_VEHICLE_VIEW, v->index);
    01496
    01497   if (v->type != VEH_TRAIN) {
    01498     /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
    01499      * 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 */
    01500     InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
    01501   }
    01502   SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
    01503
    01504   v->vehstatus |= VS_HIDDEN;
    01505   v->cur_speed = 0;
    01506
    01507   VehicleServiceInDepot(v);
    01508
    01509   TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
    01510
    01511   if (v->current_order.IsType(OT_GOTO_DEPOT)) {
    01512     SetWindowDirty(WC_VEHICLE_VIEW, v->index);
    01513
    01514     const Order *real_order = v->GetOrder(v->cur_real_order_index);
    01515     Order t = v->current_order;
    01516     v->current_order.MakeDummy();
    01517
    01518     /* Test whether we are heading for this depot. If not, do nothing.
    01519      * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
    01520     if ((t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) &&
    01521         real_order != NULL && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) &&
    01522         (v->type == VEH_AIRCRAFT ? t.GetDestination() != GetStationIndex(v->tile) : v->dest_tile != v->tile)) {
    01523       /* We are heading for another depot, keep driving. */
    01524       return;
    01525     }
    01526
    01527     if (t.IsRefit()) {
    01528       Backup<CompanyByte> cur_company(_current_company, v->owner, FILE_LINE);
    01529       CommandCost cost = DoCommand(v->tile, v->index, t.GetRefitCargo() | t.GetRefitSubtype() << 8, DC_EXEC, GetCmdRefitVeh(v));
    01530       cur_company.Restore();
    01531
    01532       if (cost.Failed()) {
    01533         _vehicles_to_autoreplace[v] = false;
    01534         if (v->owner == _local_company) {
    01535           /* Notify the user that we stopped the vehicle */
    01536           SetDParam(0, v->index);
    01537           AddVehicleNewsItem(STR_NEWS_ORDER_REFIT_FAILED, NS_ADVICE, v->index);
    01538         }
    01539       } else if (cost.GetCost() != 0) {
    01540         v->profit_this_year -= cost.GetCost() << 8;
    01541         if (v->owner == _local_company) {
    01542           ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
    01543         }
    01544       }
    01545     }
    01546
    01547     if (t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
    01548       /* Part of orders */
    01549       v->DeleteUnreachedImplicitOrders();
    01550       UpdateVehicleTimetable(v, true);
    01551       v->IncrementImplicitOrderIndex();
    01552     }
    01553     if (t.GetDepotActionType() & ODATFB_HALT) {
    01554       /* Vehicles are always stopped on entering depots. Do not restart this one. */
    01555       if (_settings_game.order.timetable_separation) v->ClearSeparation();
    01556       if (_settings_game.order.timetable_separation) ClrBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
    01557       _vehicles_to_autoreplace[v] = false;
    01558       if (v->owner == _local_company) {
    01559         SetDParam(0, v->index);
    01560         AddVehicleNewsItem(STR_NEWS_TRAIN_IS_WAITING + v->type, NS_ADVICE, v->index);
    01561       }
    01562       AI::NewEvent(v->owner, new AIEventVehicleWaitingInDepot(v->index));
    01563     }
    01564   }
    01565 }
    01566
    01567
    01575 void VehicleMove(Vehicle *v, bool update_viewport)
    01576 {
    01577   int img = v->cur_image;
    01578   Point pt = RemapCoords(v->x_pos + v->x_offs, v->y_pos + v->y_offs, v->z_pos);
    01579   const Sprite *spr = GetSprite(img, ST_NORMAL);
    01580
    01581   pt.x += spr->x_offs;
    01582   pt.y += spr->y_offs;
    01583
    01584   UpdateVehiclePosHash(v, pt.x, pt.y);
    01585
    01586   Rect old_coord = v->coord;
    01587   v->coord.left   = pt.x;
    01588   v->coord.top    = pt.y;
    01589   v->coord.right  = pt.x + spr->width + 2;
    01590   v->coord.bottom = pt.y + spr->height + 2;
    01591
    01592   if (update_viewport) {
    01593     MarkAllViewportsDirty(
    01594       min(old_coord.left,   v->coord.left),
    01595       min(old_coord.top,    v->coord.top),
    01596       max(old_coord.right,  v->coord.right) + 1,
    01597       max(old_coord.bottom, v->coord.bottom) + 1
    01598     );
    01599   }
    01600 }
    01601
    01610 void MarkSingleVehicleDirty(const Vehicle *v)
    01611 {
    01612   MarkAllViewportsDirty(v->coord.left, v->coord.top, v->coord.right + 1, v->coord.bottom + 1);
    01613 }
    01614
    01620 GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
    01621 {
    01622   static const int8 _delta_coord[16] = {
    01623     -1,-1,-1, 0, 1, 1, 1, 0, /* x */
    01624     -1, 0, 1, 1, 1, 0,-1,-1, /* y */
    01625   };
    01626
    01627   int x = v->x_pos + _delta_coord[v->direction];
    01628   int y = v->y_pos + _delta_coord[v->direction + 8];
    01629
    01630   GetNewVehiclePosResult gp;
    01631   gp.x = x;
    01632   gp.y = y;
    01633   gp.old_tile = v->tile;
    01634   gp.new_tile = TileVirtXY(x, y);
    01635   return gp;
    01636 }
    01637
    01638 static const Direction _new_direction_table[] = {
    01639   DIR_N,  DIR_NW, DIR_W,
    01640   DIR_NE, DIR_SE, DIR_SW,
    01641   DIR_E,  DIR_SE, DIR_S
    01642 };
    01643
    01644 Direction GetDirectionTowards(const Vehicle *v, int x, int y)
    01645 {
    01646   int i = 0;
    01647
    01648   if (y >= v->y_pos) {
    01649     if (y != v->y_pos) i += 3;
    01650     i += 3;
    01651   }
    01652
    01653   if (x >= v->x_pos) {
    01654     if (x != v->x_pos) i++;
    01655     i++;
    01656   }
    01657
    01658   Direction dir = v->direction;
    01659
    01660   DirDiff dirdiff = DirDifference(_new_direction_table[i], dir);
    01661   if (dirdiff == DIRDIFF_SAME) return dir;
    01662   return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
    01663 }
    01664
    01674 VehicleEnterTileStatus VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
    01675 {
    01676   return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
    01677 }
    01678
    01686 FreeUnitIDGenerator::FreeUnitIDGenerator(VehicleType type, CompanyID owner) : cache(NULL), maxid(0), curid(0)
    01687 {
    01688   /* Find maximum */
    01689   const Vehicle *v;
    01690   FOR_ALL_VEHICLES(v) {
    01691     if (v->type == type && v->owner == owner) {
    01692       this->maxid = max<UnitID>(this->maxid, v->unitnumber);
    01693     }
    01694   }
    01695
    01696   if (this->maxid == 0) return;
    01697
    01698   /* Reserving 'maxid + 2' because we need:
    01699    * - space for the last item (with v->unitnumber == maxid)
    01700    * - one free slot working as loop terminator in FreeUnitIDGenerator::NextID() */
    01701   this->cache = CallocT<bool>(this->maxid + 2);
    01702
    01703   /* Fill the cache */
    01704   FOR_ALL_VEHICLES(v) {
    01705     if (v->type == type && v->owner == owner) {
    01706       this->cache[v->unitnumber] = true;
    01707     }
    01708   }
    01709 }
    01710
    01712 UnitID FreeUnitIDGenerator::NextID()
    01713 {
    01714   if (this->maxid <= this->curid) return ++this->curid;
    01715
    01716   while (this->cache[++this->curid]) { } // it will stop, we reserved more space than needed
    01717
    01718   return this->curid;
    01719 }
    01720
    01726 UnitID GetFreeUnitNumber(VehicleType type)
    01727 {
    01728   /* Check whether it is allowed to build another vehicle. */
    01729   uint max_veh;
    01730   switch (type) {
    01731     case VEH_TRAIN:    max_veh = _settings_game.vehicle.max_trains;   break;
    01732     case VEH_ROAD:     max_veh = _settings_game.vehicle.max_roadveh;  break;
    01733     case VEH_SHIP:     max_veh = _settings_game.vehicle.max_ships;    break;
    01734     case VEH_AIRCRAFT: max_veh = _settings_game.vehicle.max_aircraft; break;
    01735     default: NOT_REACHED();
    01736   }
    01737
    01738   uint amounts[4];
    01739   CountCompanyVehicles(_current_company, amounts);
    01740   assert((uint)type < lengthof(amounts));
    01741   if (amounts[type] >= max_veh) return UINT16_MAX; // Currently already at the limit, no room to make a new one.
    01742
    01743   FreeUnitIDGenerator gen(type, _current_company);
    01744
    01745   return gen.NextID();
    01746 }
    01747
    01748
    01757 bool CanBuildVehicleInfrastructure(VehicleType type)
    01758 {
    01759   assert(IsCompanyBuildableVehicleType(type));
    01760
    01761   if (!Company::IsValidID(_local_company)) return false;
    01762   if (!_settings_client.gui.disable_unsuitable_building) return true;
    01763
    01764   UnitID max;
    01765   switch (type) {
    01766     case VEH_TRAIN:    max = _settings_game.vehicle.max_trains; break;
    01767     case VEH_ROAD:     max = _settings_game.vehicle.max_roadveh; break;
    01768     case VEH_SHIP:     max = _settings_game.vehicle.max_ships; break;
    01769     case VEH_AIRCRAFT: max = _settings_game.vehicle.max_aircraft; break;
    01770     default: NOT_REACHED();
    01771   }
    01772
    01773   /* We can build vehicle infrastructure when we may build the vehicle type */
    01774   if (max > 0) {
    01775     /* Can we actually build the vehicle type? */
    01776     const Engine *e;
    01777     FOR_ALL_ENGINES_OF_TYPE(e, type) {
    01778       if (HasBit(e->company_avail, _local_company)) return true;
    01779     }
    01780     return false;
    01781   }
    01782
    01783   /* We should be able to build infrastructure when we have the actual vehicle type */
    01784   const Vehicle *v;
    01785   FOR_ALL_VEHICLES(v) {
    01786     if (v->owner == _local_company && v->type == type) return true;
    01787   }
    01788
    01789   return false;
    01790 }
    01791
    01792
    01800 LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
    01801 {
    01802   CargoID cargo_type = v == NULL ? (CargoID)CT_INVALID : v->cargo_type;
    01803   const Engine *e = Engine::Get(engine_type);
    01804   switch (e->type) {
    01805     default: NOT_REACHED();
    01806     case VEH_TRAIN:
    01807       if (v != NULL && parent_engine_type != INVALID_ENGINE && (UsesWagonOverride(v) || (v->IsArticulatedPart() && e->u.rail.railveh_type != RAILVEH_WAGON))) {
    01808         /* Wagonoverrides use the colour scheme of the front engine.
    01809          * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */
    01810         engine_type = parent_engine_type;
    01811         e = Engine::Get(engine_type);
    01812         /* Note: Luckily cargo_type is not needed for engines */
    01813       }
    01814
    01815       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01816       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01817       if (e->u.rail.railveh_type == RAILVEH_WAGON) {
    01818         if (!CargoSpec::Get(cargo_type)->is_freight) {
    01819           if (parent_engine_type == INVALID_ENGINE) {
    01820             return LS_PASSENGER_WAGON_STEAM;
    01821           } else {
    01822             switch (RailVehInfo(parent_engine_type)->engclass) {
    01823               default: NOT_REACHED();
    01824               case EC_STEAM:    return LS_PASSENGER_WAGON_STEAM;
    01825               case EC_DIESEL:   return LS_PASSENGER_WAGON_DIESEL;
    01826               case EC_ELECTRIC: return LS_PASSENGER_WAGON_ELECTRIC;
    01827               case EC_MONORAIL: return LS_PASSENGER_WAGON_MONORAIL;
    01828               case EC_MAGLEV:   return LS_PASSENGER_WAGON_MAGLEV;
    01829             }
    01830           }
    01831         } else {
    01832           return LS_FREIGHT_WAGON;
    01833         }
    01834       } else {
    01835         bool is_mu = HasBit(e->info.misc_flags, EF_RAIL_IS_MU);
    01836
    01837         switch (e->u.rail.engclass) {
    01838           default: NOT_REACHED();
    01839           case EC_STEAM:    return LS_STEAM;
    01840           case EC_DIESEL:   return is_mu ? LS_DMU : LS_DIESEL;
    01841           case EC_ELECTRIC: return is_mu ? LS_EMU : LS_ELECTRIC;
    01842           case EC_MONORAIL: return LS_MONORAIL;
    01843           case EC_MAGLEV:   return LS_MAGLEV;
    01844         }
    01845       }
    01846
    01847     case VEH_ROAD:
    01848       /* Always use the livery of the front */
    01849       if (v != NULL && parent_engine_type != INVALID_ENGINE) {
    01850         engine_type = parent_engine_type;
    01851         e = Engine::Get(engine_type);
    01852         cargo_type = v->First()->cargo_type;
    01853       }
    01854       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01855       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01856
    01857       /* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */
    01858       if (HasBit(e->info.misc_flags, EF_ROAD_TRAM)) {
    01859         /* Tram */
    01860         return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
    01861       } else {
    01862         /* Bus or truck */
    01863         return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_BUS : LS_TRUCK;
    01864       }
    01865
    01866     case VEH_SHIP:
    01867       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01868       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01869       return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
    01870
    01871     case VEH_AIRCRAFT:
    01872       switch (e->u.air.subtype) {
    01873         case AIR_HELI: return LS_HELICOPTER;
    01874         case AIR_CTOL: return LS_SMALL_PLANE;
    01875         case AIR_CTOL | AIR_FAST: return LS_LARGE_PLANE;
    01876         default: NOT_REACHED();
    01877       }
    01878   }
    01879 }
    01880
    01890 const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, byte livery_setting)
    01891 {
    01892   const Company *c = Company::Get(company);
    01893   LiveryScheme scheme = LS_DEFAULT;
    01894
    01895   /* The default livery is always available for use, but its in_use flag determines
    01896    * whether any _other_ liveries are in use. */
    01897   if (c->livery[LS_DEFAULT].in_use && (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company))) {
    01898     /* Determine the livery scheme to use */
    01899     scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
    01900
    01901     /* Switch back to the default scheme if the resolved scheme is not in use */
    01902     if (!c->livery[scheme].in_use) scheme = LS_DEFAULT;
    01903   }
    01904
    01905   return &c->livery[scheme];
    01906 }
    01907
    01908
    01909 static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
    01910 {
    01911   PaletteID map = (v != NULL) ? v->colourmap : PAL_NONE;
    01912
    01913   /* Return cached value if any */
    01914   if (map != PAL_NONE) return map;
    01915
    01916   const Engine *e = Engine::Get(engine_type);
    01917
    01918   /* Check if we should use the colour map callback */
    01919   if (HasBit(e->info.callback_mask, CBM_VEHICLE_COLOUR_REMAP)) {
    01920     uint16 callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
    01921     /* Failure means "use the default two-colour" */
    01922     if (callback != CALLBACK_FAILED) {
    01923       assert_compile(PAL_NONE == 0); // Returning 0x4000 (resp. 0xC000) conincidences with default value (PAL_NONE)
    01924       map = GB(callback, 0, 14);
    01925       /* If bit 14 is set, then the company colours are applied to the
    01926        * map else it's returned as-is. */
    01927       if (!HasBit(callback, 14)) {
    01928         /* Update cache */
    01929         if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
    01930         return map;
    01931       }
    01932     }
    01933   }
    01934
    01935   bool twocc = HasBit(e->info.misc_flags, EF_USES_2CC);
    01936
    01937   if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
    01938
    01939   /* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
    01940   if (!Company::IsValidID(company)) return map;
    01941
    01942   const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries);
    01943
    01944   map += livery->colour1;
    01945   if (twocc) map += livery->colour2 * 16;
    01946
    01947   /* Update cache */
    01948   if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
    01949   return map;
    01950 }
    01951
    01958 PaletteID GetEnginePalette(EngineID engine_type, CompanyID company)
    01959 {
    01960   return GetEngineColourMap(engine_type, company, INVALID_ENGINE, NULL);
    01961 }
    01962
    01968 PaletteID GetVehiclePalette(const Vehicle *v)
    01969 {
    01970   if (v->IsGroundVehicle()) {
    01971     return GetEngineColourMap(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v);
    01972   }
    01973
    01974   return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
    01975 }
    01976
    01985 uint GetVehicleCapacity(const Vehicle *v, uint16 *mail_capacity)
    01986 {
    01987   if (mail_capacity != NULL) *mail_capacity = 0;
    01988   const Engine *e = Engine::Get(v->engine_type);
    01989
    01990   if (!e->CanCarryCargo()) return 0;
    01991
    01992   if (mail_capacity != NULL && e->type == VEH_AIRCRAFT && IsCargoInClass(v->cargo_type, CC_PASSENGERS)) {
    01993     *mail_capacity = GetVehicleProperty(v, PROP_AIRCRAFT_MAIL_CAPACITY, e->u.air.mail_capacity);
    01994   }
    01995   CargoID default_cargo = e->GetDefaultCargoType();
    01996
    01997   /* Check the refit capacity callback if we are not in the default configuration.
    01998    * Note: This might change to become more consistent/flexible/sane, esp. when default cargo is first refittable. */
    01999   if (HasBit(e->info.callback_mask, CBM_VEHICLE_REFIT_CAPACITY) &&
    02000       (default_cargo != v->cargo_type || v->cargo_subtype != 0)) {
    02001     uint16 callback = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, v->engine_type, v);
    02002     if (callback != CALLBACK_FAILED) return callback;
    02003   }
    02004
    02005   /* Get capacity according to property resp. CB */
    02006   uint capacity;
    02007   switch (e->type) {
    02008     case VEH_TRAIN:    capacity = GetVehicleProperty(v, PROP_TRAIN_CARGO_CAPACITY,        e->u.rail.capacity); break;
    02009     case VEH_ROAD:     capacity = GetVehicleProperty(v, PROP_ROADVEH_CARGO_CAPACITY,      e->u.road.capacity); break;
    02010     case VEH_SHIP:     capacity = GetVehicleProperty(v, PROP_SHIP_CARGO_CAPACITY,         e->u.ship.capacity); break;
    02011     case VEH_AIRCRAFT: capacity = GetVehicleProperty(v, PROP_AIRCRAFT_PASSENGER_CAPACITY, e->u.air.passenger_capacity); break;
    02012     default: NOT_REACHED();
    02013   }
    02014
    02015   /* Apply multipliers depending on cargo- and vehicletype.
    02016    * Note: This might change to become more consistent/flexible. */
    02017   if (e->type != VEH_SHIP) {
    02018     if (e->type == VEH_AIRCRAFT) {
    02019       if (!IsCargoInClass(v->cargo_type, CC_PASSENGERS)) {
    02020         capacity += GetVehicleProperty(v, PROP_AIRCRAFT_MAIL_CAPACITY, e->u.air.mail_capacity);
    02021       }
    02022       if (v->cargo_type == CT_MAIL) return capacity;
    02023     } else {
    02024       switch (default_cargo) {
    02025         case CT_PASSENGERS: break;
    02026         case CT_MAIL:
    02027         case CT_GOODS: capacity *= 2; break;
    02028         default:       capacity *= 4; break;
    02029       }
    02030     }
    02031     switch (v->cargo_type) {
    02032       case CT_PASSENGERS: break;
    02033       case CT_MAIL:
    02034       case CT_GOODS: capacity /= 2; break;
    02035       default:       capacity /= 4; break;
    02036     }
    02037   }
    02038
    02039   return capacity;
    02040 }
    02041
    02045 void Vehicle::DeleteUnreachedImplicitOrders()
    02046 {
    02047   if (this->IsGroundVehicle()) {
    02048     uint16 &gv_flags = this->GetGroundVehicleFlags();
    02049     if (HasBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS)) {
    02050       /* Do not delete orders, only skip them */
    02051       ClrBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
    02052       this->cur_implicit_order_index = this->cur_real_order_index;
    02053       InvalidateVehicleOrder(this, 0);
    02054       return;
    02055     }
    02056   }
    02057
    02058   const Order *order = this->GetOrder(this->cur_implicit_order_index);
    02059   while (order != NULL) {
    02060     if (this->cur_implicit_order_index == this->cur_real_order_index) break;
    02061
    02062     if (order->IsType(OT_IMPLICIT)) {
    02063       /* Delete order effectively deletes order, so get the next before deleting it. */
    02064       order = order->next;
    02065       DeleteOrder(this, this->cur_implicit_order_index);
    02066     } else {
    02067       /* Skip non-implicit orders, e.g. service-orders */
    02068       order = order->next;
    02069       this->cur_implicit_order_index++;
    02070     }
    02071
    02072     /* Wrap around */
    02073     if (order == NULL) {
    02074       order = this->GetOrder(0);
    02075       this->cur_implicit_order_index = 0;
    02076     }
    02077   }
    02078 }
    02079
    02084 void Vehicle::BeginLoading()
    02085 {
    02086   assert(IsTileType(this->tile, MP_STATION) || this->type == VEH_SHIP);
    02087
    02088   if (this->current_order.IsType(OT_GOTO_STATION) &&
    02089       this->current_order.GetDestination() == this->last_station_visited) {
    02090     this->DeleteUnreachedImplicitOrders();
    02091
    02092     /* Now both order indices point to the destination station, and we can start loading */
    02093     this->current_order.MakeLoading(true);
    02094     UpdateVehicleTimetable(this, true);
    02095
    02096     /* Furthermore add the Non Stop flag to mark that this station
    02097      * is the actual destination of the vehicle, which is (for example)
    02098      * necessary to be known for HandleTrainLoading to determine
    02099      * whether the train is lost or not; not marking a train lost
    02100      * that arrives at random stations is bad. */
    02101     this->current_order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
    02102
    02103   } else {
    02104     /* We weren't scheduled to stop here. Insert an implicit order
    02105      * to show that we are stopping here, but only do that if the order
    02106      * list isn't empty.
    02107      * While only groundvehicles have implicit orders, e.g. aircraft might still enter
    02108      * the 'wrong' terminal when skipping orders etc. */
    02109     Order *in_list = this->GetOrder(this->cur_implicit_order_index);
    02110     if (this->IsGroundVehicle() && in_list != NULL &&
    02111         (!in_list->IsType(OT_IMPLICIT) ||
    02112         in_list->GetDestination() != this->last_station_visited)) {
    02113       bool suppress_implicit_orders = HasBit(this->GetGroundVehicleFlags(), GVF_SUPPRESS_IMPLICIT_ORDERS);
    02114       /* Do not create consecutive duplicates of implicit orders */
    02115       Order *prev_order = this->cur_implicit_order_index > 0 ? this->GetOrder(this->cur_implicit_order_index - 1) : (this->GetNumOrders() > 1 ? this->GetLastOrder() : NULL);
    02116       if (prev_order == NULL ||
    02117           (!prev_order->IsType(OT_IMPLICIT) && !prev_order->IsType(OT_GOTO_STATION)) ||
    02118           prev_order->GetDestination() != this->last_station_visited) {
    02119
    02120         /* Prefer deleting implicit orders instead of inserting new ones,
    02121          * so test whether the right order follows later */
    02122         int target_index = this->cur_implicit_order_index;
    02123         bool found = false;
    02124         while (target_index != this->cur_real_order_index) {
    02125           const Order *order = this->GetOrder(target_index);
    02126           if (order->IsType(OT_IMPLICIT) && order->GetDestination() == this->last_station_visited) {
    02127             found = true;
    02128             break;
    02129           }
    02130           target_index++;
    02131           if (target_index >= this->orders.list->GetNumOrders()) target_index = 0;
    02132           assert(target_index != this->cur_implicit_order_index); // infinite loop?
    02133         }
    02134
    02135         if (found) {
    02136           if (suppress_implicit_orders) {
    02137             /* Skip to the found order */
    02138             this->cur_implicit_order_index = target_index;
    02139             InvalidateVehicleOrder(this, 0);
    02140           } else {
    02141             /* Delete all implicit orders up to the station we just reached */
    02142             const Order *order = this->GetOrder(this->cur_implicit_order_index);
    02143             while (!order->IsType(OT_IMPLICIT) || order->GetDestination() != this->last_station_visited) {
    02144               if (order->IsType(OT_IMPLICIT)) {
    02145                 /* Delete order effectively deletes order, so get the next before deleting it. */
    02146                 order = order->next;
    02147                 DeleteOrder(this, this->cur_implicit_order_index);
    02148               } else {
    02149                 /* Skip non-implicit orders, e.g. service-orders */
    02150                 order = order->next;
    02151                 this->cur_implicit_order_index++;
    02152               }
    02153
    02154               /* Wrap around */
    02155               if (order == NULL) {
    02156                 order = this->GetOrder(0);
    02157                 this->cur_implicit_order_index = 0;
    02158               }
    02159               assert(order != NULL);
    02160             }
    02161           }
    02162         } else if (!suppress_implicit_orders && this->orders.list->GetNumOrders() < MAX_VEH_ORDER_ID && Order::CanAllocateItem()) {
    02163           /* Insert new implicit order */
    02164           Order *implicit_order = new Order();
    02165           implicit_order->MakeImplicit(this->last_station_visited);
    02166           InsertOrder(this, implicit_order, this->cur_implicit_order_index);
    02167           if (this->cur_implicit_order_index > 0) --this->cur_implicit_order_index;
    02168
    02169           /* InsertOrder disabled creation of implicit orders for all vehicles with the same implicit order.
    02170            * Reenable it for this vehicle */
    02171           uint16 &gv_flags = this->GetGroundVehicleFlags();
    02172           ClrBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
    02173         }
    02174       }
    02175     }
    02176     this->current_order.MakeLoading(false);
    02177   }
    02178
    02179   Station *curr_station = Station::Get(this->last_station_visited);
    02180   curr_station->loading_vehicles.push_back(this);
    02181
    02182   StationID next_station_id = INVALID_STATION;
    02183   OrderList *orders = this->orders.list;
    02184   if (orders != NULL) {
    02185     next_station_id = orders->GetNextStoppingStation(this->cur_implicit_order_index, this->last_station_visited);
    02186   }
    02187
    02188   if (this->last_loading_station != INVALID_STATION && this->last_loading_station != this->last_station_visited) {
    02189     IncreaseStats(Station::Get(this->last_loading_station), this, this->last_station_visited, false);
    02190   }
    02191
    02192   if (this->CanLeaveWithCargo() && next_station_id != INVALID_STATION) {
    02193     assert(next_station_id != this->last_station_visited);
    02194     /* freeze stats for the next link */
    02195     IncreaseStats(curr_station, this, next_station_id, true);
    02196   }
    02197
    02198   PrepareUnload(curr_station, this, next_station_id);
    02199
    02200   SetWindowDirty(GetWindowClassForVehicleType(this->type), this->owner);
    02201   SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    02202   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
    02203   SetWindowDirty(WC_STATION_VIEW, this->last_station_visited);
    02204
    02205   Station::Get(this->last_station_visited)->MarkTilesDirty(true);
    02206   this->cur_speed = 0;
    02207   this->MarkDirty();
    02208 }
    02209
    02214 void Vehicle::CancelReservation(StationID next, Station *st)
    02215 {
    02216   for (Vehicle *v = this; v != NULL; v = v->next) {
    02217     VehicleCargoList &cargo = v->cargo;
    02218     if (cargo.ReservedCount() > 0) {
    02219       DEBUG(misc, 1, "cancelling cargo reservation");
    02220       GoodsEntry &ge = st->goods[v->cargo_type];
    02221       cargo.Unreserve(next, &ge.cargo);
    02222       SetBit(ge.acceptance_pickup, GoodsEntry::GES_PICKUP);
    02223     }
    02224   }
    02225 }
    02226
    02233 bool Vehicle::CanLeaveWithCargo()
    02234 {
    02235   return (this->current_order.GetLoadType() & OLFB_NO_LOAD) == 0 ||
    02236       ((this->current_order.GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == 0 &&
    02237       this->last_loading_station != INVALID_STATION);
    02238 }
    02239
    02244 void Vehicle::LeaveStation()
    02245 {
    02246   assert(this->current_order.IsType(OT_LOADING));
    02247
    02248   delete this->cargo_payment;
    02249
    02250   /* Only update the timetable if the vehicle was supposed to stop here. */
    02251   if (this->current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE) UpdateVehicleTimetable(this, false);
    02252
    02253   this->current_order.MakeLeaveStation();
    02254   Station *st = Station::Get(this->last_station_visited);
    02255   st->loading_vehicles.remove(this);
    02256
    02257   OrderList *orders = this->orders.list;
    02258   if (orders != NULL) {
    02259     StationID next_station_id = orders->GetNextStoppingStation(this->cur_implicit_order_index, this->last_station_visited);
    02260     this->CancelReservation(next_station_id, st);
    02261     if (next_station_id != INVALID_STATION && next_station_id != this->last_station_visited) {
    02262       DecreaseFrozen(st, this, next_station_id);
    02263     }
    02264   } else {
    02265     this->CancelReservation(INVALID_STATION, st);
    02266     DEBUG(misc, 1, "orders are NULL");
    02267     RecalcFrozen(st);
    02268   }
    02269
    02270   if (this->CanLeaveWithCargo()) {
    02271     /* if the vehicle could load here or could stop with cargo loaded set the last loading station */
    02272     this->last_loading_station = this->last_station_visited;
    02273   } else {
    02274     /* if the vehicle couldn't load and had to unload or transfer everything
    02275      * set the last loading station to invalid as it will leave empty.
    02276      */
    02277     this->last_loading_station = INVALID_STATION;
    02278   }
    02279
    02280   HideFillingPercent(&this->fill_percent_te_id);
    02281
    02282   if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) {
    02283     /* Trigger station animation (trains only) */
    02284     if (IsTileType(this->tile, MP_STATION)) TriggerStationAnimation(st, this->tile, SAT_TRAIN_DEPARTS);
    02285
    02286     SetBit(Train::From(this)->flags, VRF_LEAVING_STATION);
    02287   }
    02288 }
    02289
    02290
    02296 void Vehicle::HandleLoading(bool mode)
    02297 {
    02298   switch (this->current_order.GetType()) {
    02299     case OT_LOADING: {
    02300       uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0);
    02301
    02302       /* Save time just loading took since that is what goes into the timetable */
    02303       if (_settings_game.order.timetabling && !HasBit(this->vehicle_flags, VF_LOADING_FINISHED))
    02304         this->current_loading_time = this->current_order_time;
    02305
    02306       /* Pay the loading fee for using someone else's station, if appropriate */
    02307       if (!mode && this->type != VEH_TRAIN) PayStationSharingFee(this, Station::Get(this->last_station_visited));
    02308
    02309       /* Not the first call for this tick, or still loading */
    02310       if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) ||
    02311           (_settings_game.order.timetabling && this->current_order_time < wait_time)) return;
    02312
    02313       this->PlayLeaveStationSound();
    02314
    02315       this->LeaveStation();
    02316
    02317       /* Only advance to next order if we just loaded at the current one */
    02318       const Order *order = this->GetOrder(this->cur_implicit_order_index);
    02319       if (order == NULL ||
    02320           (!order->IsType(OT_IMPLICIT) && !order->IsType(OT_GOTO_STATION)) ||
    02321           order->GetDestination() != this->last_station_visited) {
    02322         return;
    02323       }
    02324       break;
    02325     }
    02326
    02327     case OT_DUMMY: break;
    02328
    02329     default: return;
    02330   }
    02331
    02332   this->IncrementImplicitOrderIndex();
    02333 }
    02334
    02341 CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command)
    02342 {
    02343   CommandCost ret = CheckOwnership(this->owner);
    02344   if (ret.Failed()) return ret;
    02345
    02346   if (this->vehstatus & VS_CRASHED) return CMD_ERROR;
    02347   if (this->IsStoppedInDepot()) return CMD_ERROR;
    02348
    02349   if (this->current_order.IsType(OT_GOTO_DEPOT)) {
    02350     bool halt_in_depot = (this->current_order.GetDepotActionType() & ODATFB_HALT) != 0;
    02351     if (!!(command & DEPOT_SERVICE) == halt_in_depot) {
    02352       /* We called with a different DEPOT_SERVICE setting.
    02353        * Now we change the setting to apply the new one and let the vehicle head for the same depot.
    02354        * Note: the if is (true for requesting service == true for ordered to stop in depot)          */
    02355       if (flags & DC_EXEC) {
    02356         if (!(this->current_order.GetDepotOrderType() & ODTFB_BREAKDOWN)) this->current_order.SetDepotOrderType(ODTF_MANUAL);
    02357         this->current_order.SetDepotActionType(halt_in_depot ? ODATF_SERVICE_ONLY : ODATFB_HALT);
    02358         if (_settings_game.order.timetable_separation) this->ClearSeparation();
    02359         if (_settings_game.order.timetable_separation) ClrBit(this->vehicle_flags, VF_TIMETABLE_STARTED);
    02360         SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    02361       }
    02362       return CommandCost();
    02363     }
    02364
    02365     if (command & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
    02366     if (flags & DC_EXEC) {
    02367       /* If the orders to 'goto depot' are in the orders list (forced servicing),
    02368        * then skip to the next order; effectively cancelling this forced service */
    02369       if (this->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) this->IncrementRealOrderIndex();
    02370
    02371       if (this->IsGroundVehicle()) {
    02372         uint16 &gv_flags = this->GetGroundVehicleFlags();
    02373         SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
    02374       }
    02375
    02376       /* We don't cancel a breakdown-related goto depot order, we only change whether to halt or not */
    02377       if (this->current_order.GetDepotOrderType() & ODTFB_BREAKDOWN) {
    02378         this->current_order.SetDepotActionType(this->current_order.GetDepotActionType() == ODATFB_HALT ? ODATF_SERVICE_ONLY : ODATFB_HALT);
    02379       } else {
    02380         this->current_order.MakeDummy();
    02381         SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    02382       }
    02383     }
    02384     return CommandCost();
    02385   }
    02386
    02387   TileIndex location;
    02388   DestinationID destination;
    02389   bool reverse;
    02390   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};
    02391   if (!this->FindClosestDepot(&location, &destination, &reverse)) return_cmd_error(no_depot[this->type]);
    02392
    02393   if (flags & DC_EXEC) {
    02394     if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
    02395
    02396     if (_settings_game.order.timetable_separation) this->ClearSeparation();
    02397     if (_settings_game.order.timetable_separation) ClrBit(this->vehicle_flags, VF_TIMETABLE_STARTED);
    02398
    02399     if (this->IsGroundVehicle()) {
    02400       uint16 &gv_flags = this->GetGroundVehicleFlags();
    02401       SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
    02402     }
    02403
    02404     this->dest_tile = location;
    02405     this->current_order.MakeGoToDepot(destination, ODTF_MANUAL);
    02406     if (!(command & DEPOT_SERVICE)) this->current_order.SetDepotActionType(ODATFB_HALT);
    02407     SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    02408
    02409     /* If there is no depot in front, reverse automatically (trains only) */
    02410     if (this->type == VEH_TRAIN && reverse) DoCommand(this->tile, this->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
    02411
    02412     if (this->type == VEH_AIRCRAFT) {
    02413       Aircraft *a = Aircraft::From(this);
    02414       if (a->state == FLYING && a->targetairport != destination) {
    02415         /* The aircraft is now heading for a different hangar than the next in the orders */
    02416         extern void AircraftNextAirportPos_and_Order(Aircraft *a);
    02417         AircraftNextAirportPos_and_Order(a);
    02418       }
    02419     }
    02420   }
    02421
    02422   return CommandCost();
    02423
    02424 }
    02425
    02430 void Vehicle::UpdateVisualEffect(bool allow_power_change)
    02431 {
    02432   bool powered_before = HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
    02433   const Engine *e = Engine::Get(this->engine_type);
    02434
    02435   /* Evaluate properties */
    02436   byte visual_effect;
    02437   switch (e->type) {
    02438     case VEH_TRAIN: visual_effect = e->u.rail.visual_effect; break;
    02439     case VEH_ROAD:  visual_effect = e->u.road.visual_effect; break;
    02440     case VEH_SHIP:  visual_effect = e->u.ship.visual_effect; break;
    02441     default:        visual_effect = 1 << VE_DISABLE_EFFECT;  break;
    02442   }
    02443
    02444   /* Check powered wagon / visual effect callback */
    02445   if (HasBit(e->info.callback_mask, CBM_VEHICLE_VISUAL_EFFECT)) {
    02446     uint16 callback = GetVehicleCallback(CBID_VEHICLE_VISUAL_EFFECT, 0, 0, this->engine_type, this);
    02447
    02448     if (callback != CALLBACK_FAILED) {
    02449       callback = GB(callback, 0, 8);
    02450       /* Avoid accidentally setting 'visual_effect' to the default value
    02451        * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
    02452       if (callback == VE_DEFAULT) {
    02453         assert(HasBit(callback, VE_DISABLE_EFFECT));
    02454         SB(callback, VE_TYPE_START, VE_TYPE_COUNT, 0);
    02455       }
    02456       visual_effect = callback;
    02457     }
    02458   }
    02459
    02460   /* Apply default values */
    02461   if (visual_effect == VE_DEFAULT ||
    02462       (!HasBit(visual_effect, VE_DISABLE_EFFECT) && GB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT) == VE_TYPE_DEFAULT)) {
    02463     /* Only train engines have default effects.
    02464      * Note: This is independent of whether the engine is a front engine or articulated part or whatever. */
    02465     if (e->type != VEH_TRAIN || e->u.rail.railveh_type == RAILVEH_WAGON || !IsInsideMM(e->u.rail.engclass, EC_STEAM, EC_MONORAIL)) {
    02466       if (visual_effect == VE_DEFAULT) {
    02467         visual_effect = 1 << VE_DISABLE_EFFECT;
    02468       } else {
    02469         SetBit(visual_effect, VE_DISABLE_EFFECT);
    02470       }
    02471     } else {
    02472       if (visual_effect == VE_DEFAULT) {
    02473         /* Also set the offset */
    02474         visual_effect = (VE_OFFSET_CENTRE - (e->u.rail.engclass == EC_STEAM ? 4 : 0)) << VE_OFFSET_START;
    02475       }
    02476       SB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT, e->u.rail.engclass - EC_STEAM + VE_TYPE_STEAM);
    02477     }
    02478   }
    02479
    02480   this->vcache.cached_vis_effect = visual_effect;
    02481
    02482   if (!allow_power_change && powered_before != HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
    02483     ToggleBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
    02484     ShowNewGrfVehicleError(this->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_POWERED_WAGON, GBUG_VEH_POWERED_WAGON, false);
    02485   }
    02486 }
    02487
    02488 static const int8 _vehicle_smoke_pos[8] = {
    02489   1, 1, 1, 0, -1, -1, -1, 0
    02490 };
    02491
    02496 void Vehicle::ShowVisualEffect() const
    02497 {
    02498   assert(this->IsPrimaryVehicle());
    02499   bool sound = false;
    02500
    02501   /* Do not show any smoke when:
    02502    * - vehicle smoke is disabled by the player
    02503    * - the vehicle is slowing down or stopped (by the player)
    02504    * - the vehicle is moving very slowly
    02505    */
    02506   if (_settings_game.vehicle.smoke_amount == 0 ||
    02507       this->vehstatus & (VS_TRAIN_SLOWING | VS_STOPPED) ||
    02508       this->cur_speed < 2) {
    02509     return;
    02510   }
    02511   if (this->type == VEH_TRAIN) {
    02512     const Train *t = Train::From(this);
    02513     /* For trains, do not show any smoke when:
    02514      * - the train is reversing
    02515      * - is entering a station with an order to stop there and its speed is equal to maximum station entering speed
    02516      */
    02517     if (HasBit(t->flags, VRF_REVERSING) ||
    02518         (IsRailStationTile(t->tile) && t->IsFrontEngine() && t->current_order.ShouldStopAtStation(t, GetStationIndex(t->tile)) &&
    02519         t->cur_speed >= t->Train::GetCurrentMaxSpeed())) {
    02520       return;
    02521     }
    02522   }
    02523
    02524   const Vehicle *v = this;
    02525
    02526   do {
    02527     int effect_offset = GB(v->vcache.cached_vis_effect, VE_OFFSET_START, VE_OFFSET_COUNT) - VE_OFFSET_CENTRE;
    02528     byte effect_type = GB(v->vcache.cached_vis_effect, VE_TYPE_START, VE_TYPE_COUNT);
    02529     bool disable_effect = HasBit(v->vcache.cached_vis_effect, VE_DISABLE_EFFECT);
    02530
    02531     /* Show no smoke when:
    02532      * - Smoke has been disabled for this vehicle
    02533      * - The vehicle is not visible
    02534      * - The vehicle is under a bridge
    02535      * - The vehicle is on a depot tile
    02536      * - The vehicle is on a tunnel tile
    02537      * - The vehicle is a train engine that is currently unpowered */
    02538     if (disable_effect ||
    02539         v->vehstatus & VS_HIDDEN ||
    02540         (MayHaveBridgeAbove(v->tile) && IsBridgeAbove(v->tile)) ||
    02541         IsDepotTile(v->tile) ||
    02542         IsTunnelTile(v->tile) ||
    02543         (v->type == VEH_TRAIN &&
    02544         !HasPowerOnRail(Train::From(v)->railtype, GetTileRailType(v->tile)))) {
    02545       continue;
    02546     }
    02547
    02548     int x = _vehicle_smoke_pos[v->direction] * effect_offset;
    02549     int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
    02550
    02551     if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) {
    02552       x = -x;
    02553       y = -y;
    02554     }
    02555
    02556     switch (effect_type) {
    02557       case VE_TYPE_STEAM:
    02558         /* Steam smoke - amount is gradually falling until vehicle reaches its maximum speed, after that it's normal.
    02559          * Details: while vehicle's current speed is gradually increasing, steam plumes' density decreases by one third each
    02560          * third of its maximum speed spectrum. Steam emission finally normalises at very close to vehicle's maximum speed.
    02561          * REGULATION:
    02562          * - instead of 1, 4 / 2^smoke_amount (max. 2) is used to provide sufficient regulation to steam puffs' amount. */
    02563         if (GB(v->tick_counter, 0, ((4 >> _settings_game.vehicle.smoke_amount) + ((this->cur_speed * 3) / this->vcache.cached_max_speed))) == 0) {
    02564           CreateEffectVehicleRel(v, x, y, 10, EV_STEAM_SMOKE);
    02565           sound = true;
    02566         }
    02567         break;
    02568
    02569       case VE_TYPE_DIESEL: {
    02570         /* Diesel smoke - thicker when vehicle is starting, gradually subsiding till it reaches its maximum speed
    02571          * when smoke emission stops.
    02572          * Details: Vehicle's (max.) speed spectrum is divided into 32 parts. When max. speed is reached, chance for smoke
    02573          * emission erodes by 32 (1/4). For trains, power and weight come in handy too to either increase smoke emission in
    02574          * 6 steps (1000HP each) if the power is low or decrease smoke emission in 6 steps (512 tonnes each) if the train
    02575          * isn't overweight. Power and weight contributions are expressed in a way that neither extreme power, nor
    02576          * extreme weight can ruin the balance (e.g. FreightWagonMultiplier) in the formula. When the vehicle reaches
    02577          * maximum speed no diesel_smoke is emitted.
    02578          * REGULATION:
    02579          * - up to which speed a diesel vehicle is emitting smoke (with reduced/small setting only until 1/2 of max_speed),
    02580          * - in Chance16 - the last value is 512 / 2^smoke_amount (max. smoke when 128 = smoke_amount of 2). */
    02581         int power_weight_effect = 0;
    02582         if (v->type == VEH_TRAIN) {
    02583           power_weight_effect = (32 >> (Train::From(this)->gcache.cached_power >> 10)) - (32 >> (Train::From(this)->gcache.cached_weight >> 9));
    02584         }
    02585         if (this->cur_speed < (this->vcache.cached_max_speed >> (2 >> _settings_game.vehicle.smoke_amount)) &&
    02586             Chance16((64 - ((this->cur_speed << 5) / this->vcache.cached_max_speed) + power_weight_effect), (512 >> _settings_game.vehicle.smoke_amount))) {
    02587           CreateEffectVehicleRel(v, x, y, 10, EV_DIESEL_SMOKE);
    02588           sound = true;
    02589         }
    02590         break;
    02591       }
    02592
    02593       case VE_TYPE_ELECTRIC:
    02594         /* Electric train's spark - more often occurs when train is departing (more load)
    02595          * Details: Electric locomotives are usually at least twice as powerful as their diesel counterparts, so spark
    02596          * emissions are kept simple. Only when starting, creating huge force are sparks more likely to happen, but when
    02597          * reaching its max. speed, quarter by quarter of it, chance decreases untill the usuall 2,22% at train's top speed.
    02598          * REGULATION:
    02599          * - in Chance16 the last value is 360 / 2^smoke_amount (max. sparks when 90 = smoke_amount of 2). */
    02600         if (GB(v->tick_counter, 0, 2) == 0 &&
    02601             Chance16((6 - ((this->cur_speed << 2) / this->vcache.cached_max_speed)), (360 >> _settings_game.vehicle.smoke_amount))) {
    02602           CreateEffectVehicleRel(v, x, y, 10, EV_ELECTRIC_SPARK);
    02603           sound = true;
    02604         }
    02605         break;
    02606
    02607       default:
    02608         break;
    02609     }
    02610   } while ((v = v->Next()) != NULL);
    02611
    02612   if (sound) PlayVehicleSound(this, VSE_VISUAL_EFFECT);
    02613 }
    02614
    02619 void Vehicle::SetNext(Vehicle *next)
    02620 {
    02621   assert(this != next);
    02622
    02623   if (this->next != NULL) {
    02624     /* We had an old next vehicle. Update the first and previous pointers */
    02625     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
    02626       v->first = this->next;
    02627     }
    02628     this->next->previous = NULL;
    02629   }
    02630
    02631   this->next = next;
    02632
    02633   if (this->next != NULL) {
    02634     /* A new next vehicle. Update the first and previous pointers */
    02635     if (this->next->previous != NULL) this->next->previous->next = NULL;
    02636     this->next->previous = this;
    02637     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
    02638       v->first = this->first;
    02639     }
    02640   }
    02641 }
    02642
    02644 void Vehicle::ClearSeparation()
    02645 {
    02646   if (this->ahead_separation == NULL && this->behind_separation == NULL) return;
    02647
    02648   assert(this->ahead_separation != NULL);
    02649   assert(this->behind_separation != NULL);
    02650
    02651   this->ahead_separation->behind_separation = this->behind_separation;
    02652   this->behind_separation->ahead_separation = this->ahead_separation;
    02653
    02654   this->ahead_separation = NULL;
    02655   this->behind_separation = NULL;
    02656
    02657   SetWindowDirty(WC_VEHICLE_TIMETABLE, this->index);
    02658 }
    02659
    02665 void Vehicle::InitSeparation()
    02666 {
    02667   assert(this->ahead_separation == NULL && this->behind_separation == NULL);
    02668   Vehicle *best_match = this;
    02669   int lowest_separation;
    02670   for (Vehicle *v_other = this->FirstShared(); v_other != NULL; v_other = v_other->NextShared()) {
    02671     if ((HasBit(v_other->vehicle_flags, VF_TIMETABLE_STARTED)) && v_other != this) {
    02672       if (best_match == this) {
    02673         best_match = v_other;
    02674         lowest_separation = 0; // TODO call SeparationBetween() here
    02675       } else {
    02676         int temp_sep = 0; // TODO call SeparationBetween() here
    02677         if (temp_sep < lowest_separation && temp_sep != -1) {
    02678           best_match = v_other;
    02679           lowest_separation = temp_sep;
    02680         }
    02681       }
    02682     }
    02683   }
    02684   this->AddToSeparationBehind(best_match);
    02685 }
    02686
    02692 void Vehicle::AddToSeparationBehind(Vehicle *v_other)
    02693 {
    02694   if (v_other->ahead_separation == NULL) v_other->ahead_separation = v_other;
    02695   if (v_other->behind_separation == NULL) v_other->behind_separation = v_other;
    02696
    02697   this->ahead_separation = v_other;
    02698   v_other->behind_separation->ahead_separation = this;
    02699   this->behind_separation = v_other->behind_separation;
    02700   v_other->behind_separation = this;
    02701 }
    02702
    02708 void Vehicle::AddToShared(Vehicle *shared_chain)
    02709 {
    02710   assert(this->previous_shared == NULL && this->next_shared == NULL);
    02711
    02712   if (shared_chain->orders.list == NULL) {
    02713     assert(shared_chain->previous_shared == NULL);
    02714     assert(shared_chain->next_shared == NULL);
    02715     this->orders.list = shared_chain->orders.list = new OrderList(NULL, shared_chain);
    02716   }
    02717
    02718   this->next_shared     = shared_chain->next_shared;
    02719   this->previous_shared = shared_chain;
    02720
    02721   shared_chain->next_shared = this;
    02722
    02723   if (this->next_shared != NULL) this->next_shared->previous_shared = this;
    02724
    02725   shared_chain->orders.list->AddVehicle(this);
    02726 }
    02727
    02731 void Vehicle::RemoveFromShared()
    02732 {
    02733   /* Remember if we were first and the old window number before RemoveVehicle()
    02734    * as this changes first if needed. */
    02735   bool were_first = (this->FirstShared() == this);
    02736   VehicleListIdentifier vli(VL_SHARED_ORDERS, this->type, this->owner, this->FirstShared()->index);
    02737
    02738   this->orders.list->RemoveVehicle(this);
    02739
    02740   if (!were_first) {
    02741     /* We are not the first shared one, so only relink our previous one. */
    02742     this->previous_shared->next_shared = this->NextShared();
    02743   }
    02744
    02745   if (this->next_shared != NULL) this->next_shared->previous_shared = this->previous_shared;
    02746
    02747
    02748   if (this->orders.list->GetNumVehicles() == 1) {
    02749     /* When there is only one vehicle, remove the shared order list window. */
    02750     DeleteWindowById(GetWindowClassForVehicleType(this->type), vli.Pack());
    02751     InvalidateVehicleOrder(this->FirstShared(), 0);
    02752   } else if (were_first) {
    02753     /* If we were the first one, update to the new first one.
    02754      * Note: FirstShared() is already the new first */
    02755     InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.Pack(), this->FirstShared()->index | (1U << 31));
    02756   }
    02757
    02758   this->next_shared     = NULL;
    02759   this->previous_shared = NULL;
    02760
    02761   if (_settings_game.order.timetable_separation) this->ClearSeparation();
    02762   if (_settings_game.order.timetable_separation) ClrBit(this->vehicle_flags, VF_TIMETABLE_STARTED);
    02763 }
    02764
    02765 void VehiclesYearlyLoop()
    02766 {
    02767   Vehicle *v;
    02768   FOR_ALL_VEHICLES(v) {
    02769     if (v->IsPrimaryVehicle()) {
    02770       /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
    02771       Money profit = v->GetDisplayProfitThisYear();
    02772       if (v->age >= 730 && profit < 0) {
    02773         if (_settings_client.gui.vehicle_income_warn && v->owner == _local_company) {
    02774           SetDParam(0, v->index);
    02775           SetDParam(1, profit);
    02776           AddVehicleNewsItem(
    02777             STR_NEWS_VEHICLE_IS_UNPROFITABLE,
    02778             NS_ADVICE,
    02779             v->index
    02780           );
    02781         }
    02782         AI::NewEvent(v->owner, new AIEventVehicleUnprofitable(v->index));
    02783       }
    02784
    02785       v->profit_last_year = v->profit_this_year;
    02786       v->profit_this_year = 0;
    02787       SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    02788     }
    02789   }
    02790 }
    02791
    02792
    02802 bool CanVehicleUseStation(EngineID engine_type, const Station *st)
    02803 {
    02804   const Engine *e = Engine::GetIfValid(engine_type);
    02805   assert(e != NULL);
    02806
    02807   switch (e->type) {
    02808     case VEH_TRAIN:
    02809       return (st->facilities & FACIL_TRAIN) != 0;
    02810
    02811     case VEH_ROAD:
    02812       /* For road vehicles we need the vehicle to know whether it can actually
    02813        * use the station, but if it doesn't have facilities for RVs it is
    02814        * certainly not possible that the station can be used. */
    02815       return (st->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP)) != 0;
    02816
    02817     case VEH_SHIP:
    02818       return (st->facilities & FACIL_DOCK) != 0;
    02819
    02820     case VEH_AIRCRAFT:
    02821       return (st->facilities & FACIL_AIRPORT) != 0 &&
    02822           (st->airport.GetFTA()->flags & (e->u.air.subtype & AIR_CTOL ? AirportFTAClass::AIRPLANES : AirportFTAClass::HELICOPTERS)) != 0;
    02823
    02824     default:
    02825       return false;
    02826   }
    02827 }
    02828
    02835 bool CanVehicleUseStation(const Vehicle *v, const Station *st)
    02836 {
    02837   if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != NULL;
    02838
    02839   return CanVehicleUseStation(v->engine_type, st);
    02840 }
    02841
    02847 GroundVehicleCache *Vehicle::GetGroundVehicleCache()
    02848 {
    02849   assert(this->IsGroundVehicle());
    02850   if (this->type == VEH_TRAIN) {
    02851     return &Train::From(this)->gcache;
    02852   } else {
    02853     return &RoadVehicle::From(this)->gcache;
    02854   }
    02855 }
    02856
    02862 const GroundVehicleCache *Vehicle::GetGroundVehicleCache() const
    02863 {
    02864   assert(this->IsGroundVehicle());
    02865   if (this->type == VEH_TRAIN) {
    02866     return &Train::From(this)->gcache;
    02867   } else {
    02868     return &RoadVehicle::From(this)->gcache;
    02869   }
    02870 }
    02871
    02877 uint16 &Vehicle::GetGroundVehicleFlags()
    02878 {
    02879   assert(this->IsGroundVehicle());
    02880   if (this->type == VEH_TRAIN) {
    02881     return Train::From(this)->gv_flags;
    02882   } else {
    02883     return RoadVehicle::From(this)->gv_flags;
    02884   }
    02885 }
    02886
    02892 const uint16 &Vehicle::GetGroundVehicleFlags() const
    02893 {
    02894   assert(this->IsGroundVehicle());
    02895   if (this->type == VEH_TRAIN) {
    02896     return Train::From(this)->gv_flags;
    02897   } else {
    02898     return RoadVehicle::From(this)->gv_flags;
    02899   }
    02900 }
    02901
    02910 void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8 num_vehicles)
    02911 {
    02912   if (v->type == VEH_TRAIN) {
    02913     Train *u = Train::From(v);
    02914     /* Only include whole vehicles, so start with the first articulated part */
    02915     u = u->GetFirstEnginePart();
    02916
    02917     /* Include num_vehicles vehicles, not counting articulated parts */
    02918     for (; u != NULL && num_vehicles > 0; num_vehicles--) {
    02919       do {
    02920         /* Include current vehicle in the selection. */
    02921         set.Include(u->index);
    02922
    02923         /* If the vehicle is multiheaded, add the other part too. */
    02924         if (u->IsMultiheaded()) set.Include(u->other_multiheaded_part->index);
    02925
    02926         u = u->Next();
    02927       } while (u != NULL && u->IsArticulatedPart());
    02928     }
    02929   }
    02930 }