# vehicle.cpp

Go to the documentation of this file.

    00001 /* $Id: vehicle.cpp 22152 2011-02-26 20:13:14Z rubidium $ */
    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
    00056 #include "table/strings.h"
    00057
    00058 #define GEN_HASH(x, y) ((GB((y), 6, 6) << 6) + GB((x), 7, 6))
    00059
    00060 VehicleID _new_vehicle_id;
    00061 uint16 _returned_refit_capacity;
    00062 uint16 _returned_mail_refit_capacity;
    00063 byte _age_cargo_skip_counter;
    00064
    00065
    00067 VehiclePool _vehicle_pool("Vehicle");
    00068 INSTANTIATE_POOL_METHODS(Vehicle)
    00069
    00070
    00075 bool Vehicle::NeedsAutorenewing(const Company *c) const
    00076 {
    00077   /* We can always generate the Company pointer when we have the vehicle.
    00078    * However this takes time and since the Company pointer is often present
    00079    * when this function is called then it's faster to pass the pointer as an
    00080    * argument rather than finding it again. */
    00081   assert(c == Company::Get(this->owner));
    00082
    00083   if (!c->settings.engine_renew) return false;
    00084   if (this->age - this->max_age < (c->settings.engine_renew_months * 30)) return false;
    00085   if (this->age == 0) return false; // rail cars don't age and lacks a max age
    00086
    00087   return true;
    00088 }
    00089
    00090 void VehicleServiceInDepot(Vehicle *v)
    00091 {
    00092   v->date_of_last_service = _date;
    00093   v->breakdowns_since_last_service = 0;
    00094   v->reliability = Engine::Get(v->engine_type)->reliability;
    00095   SetWindowDirty(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
    00096 }
    00097
    00104 bool Vehicle::NeedsServicing() const
    00105 {
    00106   /* Stopped or crashed vehicles will not move, as such making unmovable
    00107    * vehicles to go for service is lame. */
    00108   if (this->vehstatus & (VS_STOPPED | VS_CRASHED)) return false;
    00109
    00110   /* Are we ready for the next service cycle? */
    00111   const Company *c = Company::Get(this->owner);
    00112   if (c->settings.vehicle.servint_ispercent ?
    00113       (this->reliability >= Engine::Get(this->engine_type)->reliability * (100 - this->service_interval) / 100) :
    00114       (this->date_of_last_service + this->service_interval >= _date)) {
    00115     return false;
    00116   }
    00117
    00118   /* If we're servicing anyway, because we have not disabled servicing when
    00119    * there are no breakdowns or we are playing with breakdowns, bail out. */
    00120   if (!_settings_game.order.no_servicing_if_no_breakdowns ||
    00121       _settings_game.difficulty.vehicle_breakdowns != 0) {
    00122     return true;
    00123   }
    00124
    00125   /* Test whether there is some pending autoreplace.
    00126    * Note: We do this after the service-interval test.
    00127    * There are a lot more reasons for autoreplace to fail than we can test here reasonably. */
    00128   bool pending_replace = false;
    00129   Money needed_money = c->settings.engine_renew_money;
    00130   if (needed_money > c->money) return false;
    00131
    00132   for (const Vehicle *v = this; v != NULL; v = (v->type == VEH_TRAIN) ? Train::From(v)->GetNextUnit() : NULL) {
    00133     EngineID new_engine = EngineReplacementForCompany(c, v->engine_type, v->group_id);
    00134
    00135     /* Check engine availability */
    00136     if (new_engine == INVALID_ENGINE || !HasBit(Engine::Get(new_engine)->company_avail, v->owner)) continue;
    00137
    00138     /* Check refittability */
    00139     uint32 available_cargo_types, union_mask;
    00140     GetArticulatedRefitMasks(new_engine, true, &union_mask, &available_cargo_types);
    00141     /* Is there anything to refit? */
    00142     if (union_mask != 0) {
    00143       CargoID cargo_type;
    00144       /* We cannot refit to mixed cargoes in an automated way */
    00145       if (IsArticulatedVehicleCarryingDifferentCargos(v, &cargo_type)) continue;
    00146
    00147       /* Did the old vehicle carry anything? */
    00148       if (cargo_type != CT_INVALID) {
    00149         /* We can't refit the vehicle to carry the cargo we want */
    00150         if (!HasBit(available_cargo_types, cargo_type)) continue;
    00151       }
    00152     }
    00153
    00154     /* Check money.
    00155      * We want 2*(the price of the new vehicle) without looking at the value of the vehicle we are going to sell. */
    00156     pending_replace = true;
    00157     needed_money += 2 * Engine::Get(new_engine)->GetCost();
    00158     if (needed_money > c->money) return false;
    00159   }
    00160
    00161   return pending_replace;
    00162 }
    00163
    00169 bool Vehicle::NeedsAutomaticServicing() const
    00170 {
    00171   if (this->HasDepotOrder()) return false;
    00172   if (this->current_order.IsType(OT_LOADING)) return false;
    00173   if (this->current_order.IsType(OT_GOTO_DEPOT) && this->current_order.GetDepotOrderType() != ODTFB_SERVICE) return false;
    00174   return NeedsServicing();
    00175 }
    00176
    00177 uint Vehicle::Crash(bool flooded)
    00178 {
    00179   assert((this->vehstatus & VS_CRASHED) == 0);
    00180   assert(this->Previous() == NULL); // IsPrimaryVehicle fails for free-wagon-chains
    00181
    00182   uint pass = 0;
    00183   /* Stop the vehicle. */
    00184   if (this->IsPrimaryVehicle()) this->vehstatus |= VS_STOPPED;
    00185   /* crash all wagons, and count passengers */
    00186   for (Vehicle *v = this; v != NULL; v = v->Next()) {
    00187     if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) pass += v->cargo.Count();
    00188     v->vehstatus |= VS_CRASHED;
    00189     MarkSingleVehicleDirty(v);
    00190   }
    00191
    00192   /* Dirty some windows */
    00193   InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
    00194   SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    00195   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
    00196   SetWindowDirty(WC_VEHICLE_DEPOT, this->tile);
    00197
    00198   return pass;
    00199 }
    00200
    00201
    00210 void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical)
    00211 {
    00212   const Engine *e = Engine::Get(engine);
    00213   uint32 grfid = e->grf_prop.grffile->grfid;
    00214   GRFConfig *grfconfig = GetGRFConfig(grfid);
    00215
    00216   if (!HasBit(grfconfig->grf_bugs, bug_type)) {
    00217     SetBit(grfconfig->grf_bugs, bug_type);
    00218     SetDParamStr(0, grfconfig->GetName());
    00219     SetDParam(1, engine);
    00220     ShowErrorMessage(part1, part2, WL_CRITICAL);
    00221     if (!_networking) DoCommand(0, critical ? PM_PAUSED_ERROR : PM_PAUSED_NORMAL, 1, DC_EXEC, CMD_PAUSE);
    00222   }
    00223
    00224   /* debug output */
    00225   char buffer[512];
    00226
    00227   SetDParamStr(0, grfconfig->GetName());
    00228   GetString(buffer, part1, lastof(buffer));
    00229   DEBUG(grf, 0, "%s", buffer + 3);
    00230
    00231   SetDParam(1, engine);
    00232   GetString(buffer, part2, lastof(buffer));
    00233   DEBUG(grf, 0, "%s", buffer + 3);
    00234 }
    00235
    00240 Vehicle::Vehicle(VehicleType type)
    00241 {
    00242   this->type               = type;
    00243   this->coord.left         = INVALID_COORD;
    00244   this->group_id           = DEFAULT_GROUP;
    00245   this->fill_percent_te_id = INVALID_TE_ID;
    00246   this->first              = this;
    00247   this->colourmap          = PAL_NONE;
    00248 }
    00249
    00254 byte VehicleRandomBits()
    00255 {
    00256   return GB(Random(), 0, 8);
    00257 }
    00258
    00259 /* Size of the hash, 6 = 64 x 64, 7 = 128 x 128. Larger sizes will (in theory) reduce hash
    00260  * lookup times at the expense of memory usage. */
    00261 const int HASH_BITS = 7;
    00262 const int HASH_SIZE = 1 << HASH_BITS;
    00263 const int HASH_MASK = HASH_SIZE - 1;
    00264 const int TOTAL_HASH_SIZE = 1 << (HASH_BITS * 2);
    00265 const int TOTAL_HASH_MASK = TOTAL_HASH_SIZE - 1;
    00266
    00267 /* Resolution of the hash, 0 = 1*1 tile, 1 = 2*2 tiles, 2 = 4*4 tiles, etc.
    00268  * Profiling results show that 0 is fastest. */
    00269 const int HASH_RES = 0;
    00270
    00271 static Vehicle *_new_vehicle_position_hash[TOTAL_HASH_SIZE];
    00272
    00273 static Vehicle *VehicleFromHash(int xl, int yl, int xu, int yu, void *data, VehicleFromPosProc *proc, bool find_first)
    00274 {
    00275   for (int y = yl; ; y = (y + (1 << HASH_BITS)) & (HASH_MASK << HASH_BITS)) {
    00276     for (int x = xl; ; x = (x + 1) & HASH_MASK) {
    00277       Vehicle *v = _new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
    00278       for (; v != NULL; v = v->next_new_hash) {
    00279         Vehicle *a = proc(v, data);
    00280         if (find_first && a != NULL) return a;
    00281       }
    00282       if (x == xu) break;
    00283     }
    00284     if (y == yu) break;
    00285   }
    00286
    00287   return NULL;
    00288 }
    00289
    00290
    00302 static Vehicle *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc, bool find_first)
    00303 {
    00304   const int COLL_DIST = 6;
    00305
    00306   /* Hash area to scan is from xl,yl to xu,yu */
    00307   int xl = GB((x - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
    00308   int xu = GB((x + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
    00309   int yl = GB((y - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
    00310   int yu = GB((y + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
    00311
    00312   return VehicleFromHash(xl, yl, xu, yu, data, proc, find_first);
    00313 }
    00314
    00329 void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
    00330 {
    00331   VehicleFromPosXY(x, y, data, proc, false);
    00332 }
    00333
    00345 bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
    00346 {
    00347   return VehicleFromPosXY(x, y, data, proc, true) != NULL;
    00348 }
    00349
    00360 static Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc, bool find_first)
    00361 {
    00362   int x = GB(TileX(tile), HASH_RES, HASH_BITS);
    00363   int y = GB(TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS;
    00364
    00365   Vehicle *v = _new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
    00366   for (; v != NULL; v = v->next_new_hash) {
    00367     if (v->tile != tile) continue;
    00368
    00369     Vehicle *a = proc(v, data);
    00370     if (find_first && a != NULL) return a;
    00371   }
    00372
    00373   return NULL;
    00374 }
    00375
    00389 void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
    00390 {
    00391   VehicleFromPos(tile, data, proc, false);
    00392 }
    00393
    00404 bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
    00405 {
    00406   return VehicleFromPos(tile, data, proc, true) != NULL;
    00407 }
    00408
    00415 static Vehicle *EnsureNoVehicleProcZ(Vehicle *v, void *data)
    00416 {
    00417   byte z = *(byte*)data;
    00418
    00419   if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
    00420   if (v->z_pos > z) return NULL;
    00421
    00422   return v;
    00423 }
    00424
    00430 CommandCost EnsureNoVehicleOnGround(TileIndex tile)
    00431 {
    00432   byte z = GetTileMaxZ(tile);
    00433
    00434   /* Value v is not safe in MP games, however, it is used to generate a local
    00435    * error message only (which may be different for different machines).
    00436    * Such a message does not affect MP synchronisation.
    00437    */
    00438   Vehicle *v = VehicleFromPos(tile, &z, &EnsureNoVehicleProcZ, true);
    00439   if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
    00440   return CommandCost();
    00441 }
    00442
    00444 static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
    00445 {
    00446   if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) return NULL;
    00447   if (v == (const Vehicle *)data) return NULL;
    00448
    00449   return v;
    00450 }
    00451
    00459 CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore)
    00460 {
    00461   /* Value v is not safe in MP games, however, it is used to generate a local
    00462    * error message only (which may be different for different machines).
    00463    * Such a message does not affect MP synchronisation.
    00464    */
    00465   Vehicle *v = VehicleFromPos(tile, (void *)ignore, &GetVehicleTunnelBridgeProc, true);
    00466   if (v == NULL) v = VehicleFromPos(endtile, (void *)ignore, &GetVehicleTunnelBridgeProc, true);
    00467
    00468   if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
    00469   return CommandCost();
    00470 }
    00471
    00472 static Vehicle *EnsureNoTrainOnTrackProc(Vehicle *v, void *data)
    00473 {
    00474   TrackBits rail_bits = *(TrackBits *)data;
    00475
    00476   if (v->type != VEH_TRAIN) return NULL;
    00477
    00478   Train *t = Train::From(v);
    00479   if ((t->track != rail_bits) && !TracksOverlap(t->track | rail_bits)) return NULL;
    00480
    00481   return v;
    00482 }
    00483
    00492 CommandCost EnsureNoTrainOnTrackBits(TileIndex tile, TrackBits track_bits)
    00493 {
    00494   /* Value v is not safe in MP games, however, it is used to generate a local
    00495    * error message only (which may be different for different machines).
    00496    * Such a message does not affect MP synchronisation.
    00497    */
    00498   Vehicle *v = VehicleFromPos(tile, &track_bits, &EnsureNoTrainOnTrackProc, true);
    00499   if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
    00500   return CommandCost();
    00501 }
    00502
    00503 static void UpdateNewVehiclePosHash(Vehicle *v, bool remove)
    00504 {
    00505   Vehicle **old_hash = v->old_new_hash;
    00506   Vehicle **new_hash;
    00507
    00508   if (remove) {
    00509     new_hash = NULL;
    00510   } else {
    00511     int x = GB(TileX(v->tile), HASH_RES, HASH_BITS);
    00512     int y = GB(TileY(v->tile), HASH_RES, HASH_BITS) << HASH_BITS;
    00513     new_hash = &_new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
    00514   }
    00515
    00516   if (old_hash == new_hash) return;
    00517
    00518   /* Remove from the old position in the hash table */
    00519   if (old_hash != NULL) {
    00520     if (v->next_new_hash != NULL) v->next_new_hash->prev_new_hash = v->prev_new_hash;
    00521     *v->prev_new_hash = v->next_new_hash;
    00522   }
    00523
    00524   /* Insert vehicle at beginning of the new position in the hash table */
    00525   if (new_hash != NULL) {
    00526     v->next_new_hash = *new_hash;
    00527     if (v->next_new_hash != NULL) v->next_new_hash->prev_new_hash = &v->next_new_hash;
    00528     v->prev_new_hash = new_hash;
    00529     *new_hash = v;
    00530   }
    00531
    00532   /* Remember current hash position */
    00533   v->old_new_hash = new_hash;
    00534 }
    00535
    00536 static Vehicle *_vehicle_position_hash[0x1000];
    00537
    00538 static void UpdateVehiclePosHash(Vehicle *v, int x, int y)
    00539 {
    00540   UpdateNewVehiclePosHash(v, x == INVALID_COORD);
    00541
    00542   Vehicle **old_hash, **new_hash;
    00543   int old_x = v->coord.left;
    00544   int old_y = v->coord.top;
    00545
    00546   new_hash = (x == INVALID_COORD) ? NULL : &_vehicle_position_hash[GEN_HASH(x, y)];
    00547   old_hash = (old_x == INVALID_COORD) ? NULL : &_vehicle_position_hash[GEN_HASH(old_x, old_y)];
    00548
    00549   if (old_hash == new_hash) return;
    00550
    00551   /* remove from hash table? */
    00552   if (old_hash != NULL) {
    00553     if (v->next_hash != NULL) v->next_hash->prev_hash = v->prev_hash;
    00554     *v->prev_hash = v->next_hash;
    00555   }
    00556
    00557   /* insert into hash table? */
    00558   if (new_hash != NULL) {
    00559     v->next_hash = *new_hash;
    00560     if (v->next_hash != NULL) v->next_hash->prev_hash = &v->next_hash;
    00561     v->prev_hash = new_hash;
    00562     *new_hash = v;
    00563   }
    00564 }
    00565
    00566 void ResetVehiclePosHash()
    00567 {
    00568   Vehicle *v;
    00569   FOR_ALL_VEHICLES(v) { v->old_new_hash = NULL; }
    00570   memset(_vehicle_position_hash, 0, sizeof(_vehicle_position_hash));
    00571   memset(_new_vehicle_position_hash, 0, sizeof(_new_vehicle_position_hash));
    00572 }
    00573
    00574 void ResetVehicleColourMap()
    00575 {
    00576   Vehicle *v;
    00577   FOR_ALL_VEHICLES(v) { v->colourmap = PAL_NONE; }
    00578 }
    00579
    00584 typedef SmallMap<Vehicle *, bool, 4> AutoreplaceMap;
    00585 static AutoreplaceMap _vehicles_to_autoreplace;
    00586
    00587 void InitializeVehicles()
    00588 {
    00589   _vehicle_pool.CleanPool();
    00590   _cargo_payment_pool.CleanPool();
    00591
    00592   _age_cargo_skip_counter = 1;
    00593
    00594   _vehicles_to_autoreplace.Reset();
    00595   ResetVehiclePosHash();
    00596 }
    00597
    00598 uint CountVehiclesInChain(const Vehicle *v)
    00599 {
    00600   uint count = 0;
    00601   do count++; while ((v = v->Next()) != NULL);
    00602   return count;
    00603 }
    00604
    00610 void CountCompanyVehicles(CompanyID cid, uint counts[4])
    00611 {
    00612   for (uint i = 0; i < 4; i++) counts[i] = 0;
    00613
    00614   const Vehicle *v;
    00615   FOR_ALL_VEHICLES(v) {
    00616     if (v->owner == cid && v->IsPrimaryVehicle()) counts[v->type]++;
    00617   }
    00618 }
    00619
    00624 bool Vehicle::IsEngineCountable() const
    00625 {
    00626   switch (this->type) {
    00627     case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft(); // don't count plane shadows and helicopter rotors
    00628     case VEH_TRAIN:
    00629       return !this->IsArticulatedPart() && // tenders and other articulated parts
    00630           !Train::From(this)->IsRearDualheaded(); // rear parts of multiheaded engines
    00631     case VEH_ROAD: return RoadVehicle::From(this)->IsFrontEngine();
    00632     case VEH_SHIP: return true;
    00633     default: return false; // Only count company buildable vehicles
    00634   }
    00635 }
    00636
    00644 void Vehicle::HandlePathfindingResult(bool path_found)
    00645 {
    00646   if (path_found) {
    00647     /* Route found, is the vehicle marked with "lost" flag? */
    00648     if (!HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;
    00649
    00650     /* Clear the flag as the PF's problem was solved. */
    00651     ClrBit(this->vehicle_flags, VF_PATHFINDER_LOST);
    00652     /* Delete the news item. */
    00653     DeleteVehicleNews(this->index, STR_NEWS_VEHICLE_IS_LOST);
    00654     return;
    00655   }
    00656
    00657   /* Were we already lost? */
    00658   if (HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;
    00659
    00660   /* It is first time the problem occurred, set the "lost" flag. */
    00661   SetBit(this->vehicle_flags, VF_PATHFINDER_LOST);
    00662   /* Notify user about the event. */
    00663   AI::NewEvent(this->owner, new AIEventVehicleLost(this->index));
    00664   if (_settings_client.gui.lost_vehicle_warn && this->owner == _local_company) {
    00665     SetDParam(0, this->index);
    00666     AddVehicleNewsItem(STR_NEWS_VEHICLE_IS_LOST, NS_ADVICE, this->index);
    00667   }
    00668 }
    00669
    00671 void Vehicle::PreDestructor()
    00672 {
    00673   if (CleaningPool()) return;
    00674
    00675   if (Station::IsValidID(this->last_station_visited)) {
    00676     Station::Get(this->last_station_visited)->loading_vehicles.remove(this);
    00677
    00678     HideFillingPercent(&this->fill_percent_te_id);
    00679
    00680     delete this->cargo_payment;
    00681   }
    00682
    00683   if (this->IsEngineCountable()) {
    00684     Company::Get(this->owner)->num_engines[this->engine_type]--;
    00685     if (this->owner == _local_company) InvalidateAutoreplaceWindow(this->engine_type, this->group_id);
    00686
    00687     DeleteGroupHighlightOfVehicle(this);
    00688     if (Group::IsValidID(this->group_id)) Group::Get(this->group_id)->num_engines[this->engine_type]--;
    00689     if (this->IsPrimaryVehicle()) DecreaseGroupNumVehicle(this->group_id);
    00690   }
    00691
    00692   if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) {
    00693     Aircraft *a = Aircraft::From(this);
    00694     Station *st = GetTargetAirportIfValid(a);
    00695     if (st != NULL) {
    00696       const AirportFTA *layout = st->airport.GetFTA()->layout;
    00697       CLRBITS(st->airport.flags, layout[a->previous_pos].block | layout[a->pos].block);
    00698     }
    00699   }
    00700
    00701
    00702   if (this->type == VEH_ROAD && this->IsPrimaryVehicle()) {
    00703     RoadVehicle *v = RoadVehicle::From(this);
    00704     if (!(v->vehstatus & VS_CRASHED) && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
    00705       /* Leave the drive through roadstop, when you have not already left it. */
    00706       RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
    00707     }
    00708   }
    00709
    00710   if (this->Previous() == NULL) {
    00711     InvalidateWindowData(WC_VEHICLE_DEPOT, this->tile);
    00712   }
    00713
    00714   if (this->IsPrimaryVehicle()) {
    00715     DeleteWindowById(WC_VEHICLE_VIEW, this->index);
    00716     DeleteWindowById(WC_VEHICLE_ORDERS, this->index);
    00717     DeleteWindowById(WC_VEHICLE_REFIT, this->index);
    00718     DeleteWindowById(WC_VEHICLE_DETAILS, this->index);
    00719     DeleteWindowById(WC_VEHICLE_TIMETABLE, this->index);
    00720     SetWindowDirty(WC_COMPANY, this->owner);
    00721     OrderBackup::ClearVehicle(this);
    00722   }
    00723   InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
    00724
    00725   this->cargo.Truncate(0);
    00726   DeleteVehicleOrders(this);
    00727   DeleteDepotHighlightOfVehicle(this);
    00728
    00729   extern void StopGlobalFollowVehicle(const Vehicle *v);
    00730   StopGlobalFollowVehicle(this);
    00731
    00732   ReleaseDisastersTargetingVehicle(this->index);
    00733 }
    00734
    00735 Vehicle::~Vehicle()
    00736 {
    00737   free(this->name);
    00738
    00739   if (CleaningPool()) return;
    00740
    00741   /* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles,
    00742    * it may happen that vehicle chain is deleted when visible */
    00743   if (!(this->vehstatus & VS_HIDDEN)) MarkSingleVehicleDirty(this);
    00744
    00745   Vehicle *v = this->Next();
    00746   this->SetNext(NULL);
    00747
    00748   delete v;
    00749
    00750   UpdateVehiclePosHash(this, INVALID_COORD, 0);
    00751   DeleteVehicleNews(this->index, INVALID_STRING_ID);
    00752   DeleteNewGRFInspectWindow(GetGrfSpecFeature(this->type), this->index);
    00753 }
    00754
    00759 void VehicleEnteredDepotThisTick(Vehicle *v)
    00760 {
    00761   /* Vehicle should stop in the depot if it was in 'stopping' state */
    00762   _vehicles_to_autoreplace[v] = !(v->vehstatus & VS_STOPPED);
    00763
    00764   /* We ALWAYS set the stopped state. Even when the vehicle does not plan on
    00765    * stopping in the depot, so we stop it to ensure that it will not reserve
    00766    * the path out of the depot before we might autoreplace it to a different
    00767    * engine. The new engine would not own the reserved path we store that we
    00768    * stopped the vehicle, so autoreplace can start it again */
    00769   v->vehstatus |= VS_STOPPED;
    00770 }
    00771
    00777 static void RunVehicleDayProc()
    00778 {
    00779   if (_game_mode != GM_NORMAL) return;
    00780
    00781   /* Run the day_proc for every DAY_TICKS vehicle starting at _date_fract. */
    00782   for (size_t i = _date_fract; i < Vehicle::GetPoolSize(); i += DAY_TICKS) {
    00783     Vehicle *v = Vehicle::Get(i);
    00784     if (v == NULL) continue;
    00785
    00786     /* Call the 32-day callback if needed */
    00787     if ((v->day_counter & 0x1F) == 0) {
    00788       uint16 callback = GetVehicleCallback(CBID_VEHICLE_32DAY_CALLBACK, 0, 0, v->engine_type, v);
    00789       if (callback != CALLBACK_FAILED) {
    00790         if (HasBit(callback, 0)) TriggerVehicle(v, VEHICLE_TRIGGER_CALLBACK_32); // Trigger vehicle trigger 10
    00791         if (HasBit(callback, 1)) v->colourmap = PAL_NONE;
    00792       }
    00793     }
    00794
    00795     /* This is called once per day for each vehicle, but not in the first tick of the day */
    00796     v->OnNewDay();
    00797   }
    00798 }
    00799
    00800 void CallVehicleTicks()
    00801 {
    00802   _vehicles_to_autoreplace.Clear();
    00803
    00804   _age_cargo_skip_counter = (_age_cargo_skip_counter == 0) ? 184 : (_age_cargo_skip_counter - 1);
    00805
    00806   RunVehicleDayProc();
    00807
    00808   Station *st;
    00809   FOR_ALL_STATIONS(st) LoadUnloadStation(st);
    00810
    00811   Vehicle *v;
    00812   FOR_ALL_VEHICLES(v) {
    00813     /* Vehicle could be deleted in this tick */
    00814     if (!v->Tick()) {
    00815       assert(Vehicle::Get(vehicle_index) == NULL);
    00816       continue;
    00817     }
    00818
    00819     assert(Vehicle::Get(vehicle_index) == v);
    00820
    00821     switch (v->type) {
    00822       default: break;
    00823
    00824       case VEH_TRAIN:
    00825       case VEH_ROAD:
    00826       case VEH_AIRCRAFT:
    00827       case VEH_SHIP:
    00828         if (_age_cargo_skip_counter == 0) v->cargo.AgeCargo();
    00829
    00830         if (v->type == VEH_TRAIN && Train::From(v)->IsWagon()) continue;
    00831         if (v->type == VEH_AIRCRAFT && v->subtype != AIR_HELICOPTER) continue;
    00832         if (v->type == VEH_ROAD && !RoadVehicle::From(v)->IsFrontEngine()) continue;
    00833
    00834         v->motion_counter += v->cur_speed;
    00835         /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
    00836         if (GB(v->motion_counter, 0, 8) < v->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
    00837
    00838         /* Play an alterate running sound every 16 ticks */
    00839         if (GB(v->tick_counter, 0, 4) == 0) PlayVehicleSound(v, v->cur_speed > 0 ? VSE_RUNNING_16 : VSE_STOPPED_16);
    00840     }
    00841   }
    00842
    00843   Backup<CompanyByte> cur_company(_current_company, FILE_LINE);
    00844   for (AutoreplaceMap::iterator it = _vehicles_to_autoreplace.Begin(); it != _vehicles_to_autoreplace.End(); it++) {
    00845     v = it->first;
    00846     /* Autoreplace needs the current company set as the vehicle owner */
    00847     cur_company.Change(v->owner);
    00848
    00849     /* Start vehicle if we stopped them in VehicleEnteredDepotThisTick()
    00850      * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that
    00851      * they are already leaving the depot again before being replaced. */
    00852     if (it->second) v->vehstatus &= ~VS_STOPPED;
    00853
    00854     /* Store the position of the effect as the vehicle pointer will become invalid later */
    00855     int x = v->x_pos;
    00856     int y = v->y_pos;
    00857     int z = v->z_pos;
    00858
    00859     const Company *c = Company::Get(_current_company);
    00860     SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, (Money)c->settings.engine_renew_money));
    00861     CommandCost res = DoCommand(0, v->index, 0, DC_EXEC, CMD_AUTOREPLACE_VEHICLE);
    00862     SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, -(Money)c->settings.engine_renew_money));
    00863
    00864     if (!IsLocalCompany()) continue;
    00865
    00866     if (res.Succeeded()) {
    00867       ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
    00868       continue;
    00869     }
    00870
    00871     StringID error_message = res.GetErrorMessage();
    00872     if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message == INVALID_STRING_ID) continue;
    00873
    00874     if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT;
    00875
    00876     StringID message;
    00877     if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
    00878       message = error_message;
    00879     } else {
    00880       message = STR_NEWS_VEHICLE_AUTORENEW_FAILED;
    00881     }
    00882
    00883     SetDParam(0, v->index);
    00884     SetDParam(1, error_message);
    00885     AddVehicleNewsItem(message, NS_ADVICE, v->index);
    00886   }
    00887
    00888   cur_company.Restore();
    00889 }
    00890
    00895 static void DoDrawVehicle(const Vehicle *v)
    00896 {
    00897   SpriteID image = v->cur_image;
    00898   PaletteID pal = PAL_NONE;
    00899
    00900   if (v->vehstatus & VS_DEFPAL) pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
    00901
    00902   AddSortableSpriteToDraw(image, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
    00903     v->x_extent, v->y_extent, v->z_extent, v->z_pos, (v->vehstatus & VS_SHADOW) != 0);
    00904 }
    00905
    00910 void ViewportAddVehicles(DrawPixelInfo *dpi)
    00911 {
    00912   /* The bounding rectangle */
    00913   const int l = dpi->left;
    00914   const int r = dpi->left + dpi->width;
    00915   const int t = dpi->top;
    00916   const int b = dpi->top + dpi->height;
    00917
    00918   /* The hash area to scan */
    00919   int xl, xu, yl, yu;
    00920
    00921   if (dpi->width + 70 < (1 << (7 + 6))) {
    00922     xl = GB(l - 70, 7, 6);
    00923     xu = GB(r,      7, 6);
    00924   } else {
    00925     /* scan whole hash row */
    00926     xl = 0;
    00927     xu = 0x3F;
    00928   }
    00929
    00930   if (dpi->height + 70 < (1 << (6 + 6))) {
    00931     yl = GB(t - 70, 6, 6) << 6;
    00932     yu = GB(b,      6, 6) << 6;
    00933   } else {
    00934     /* scan whole column */
    00935     yl = 0;
    00936     yu = 0x3F << 6;
    00937   }
    00938
    00939   for (int y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
    00940     for (int x = xl;; x = (x + 1) & 0x3F) {
    00941       const Vehicle *v = _vehicle_position_hash[x + y]; // already masked & 0xFFF
    00942
    00943       while (v != NULL) {
    00944         if (!(v->vehstatus & VS_HIDDEN) &&
    00945             l <= v->coord.right &&
    00946             t <= v->coord.bottom &&
    00947             r >= v->coord.left &&
    00948             b >= v->coord.top) {
    00949           DoDrawVehicle(v);
    00950         }
    00951         v = v->next_hash;
    00952       }
    00953
    00954       if (x == xu) break;
    00955     }
    00956
    00957     if (y == yu) break;
    00958   }
    00959 }
    00960
    00968 Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y)
    00969 {
    00970   Vehicle *found = NULL, *v;
    00971   uint dist, best_dist = UINT_MAX;
    00972
    00973   if ((uint)(x -= vp->left) >= (uint)vp->width || (uint)(y -= vp->top) >= (uint)vp->height) return NULL;
    00974
    00975   x = ScaleByZoom(x, vp->zoom) + vp->virtual_left;
    00976   y = ScaleByZoom(y, vp->zoom) + vp->virtual_top;
    00977
    00978   FOR_ALL_VEHICLES(v) {
    00979     if ((v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0 &&
    00980         x >= v->coord.left && x <= v->coord.right &&
    00981         y >= v->coord.top && y <= v->coord.bottom) {
    00982
    00983       dist = max(
    00984         abs(((v->coord.left + v->coord.right) >> 1) - x),
    00985         abs(((v->coord.top + v->coord.bottom) >> 1) - y)
    00986       );
    00987
    00988       if (dist < best_dist) {
    00989         found = v;
    00990         best_dist = dist;
    00991       }
    00992     }
    00993   }
    00994
    00995   return found;
    00996 }
    00997
    01002 void DecreaseVehicleValue(Vehicle *v)
    01003 {
    01004   v->value -= v->value >> 8;
    01005   SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    01006 }
    01007
    01008 static const byte _breakdown_chance[64] = {
    01009     3,   3,   3,   3,   3,   3,   3,   3,
    01010     4,   4,   5,   5,   6,   6,   7,   7,
    01011     8,   8,   9,   9,  10,  10,  11,  11,
    01012    12,  13,  13,  13,  13,  14,  15,  16,
    01013    17,  19,  21,  25,  28,  31,  34,  37,
    01014    40,  44,  48,  52,  56,  60,  64,  68,
    01015    72,  80,  90, 100, 110, 120, 130, 140,
    01016   150, 170, 190, 210, 230, 250, 250, 250,
    01017 };
    01018
    01019 void CheckVehicleBreakdown(Vehicle *v)
    01020 {
    01021   int rel, rel_old;
    01022
    01023   /* decrease reliability */
    01024   v->reliability = rel = max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
    01025   if ((rel_old >> 8) != (rel >> 8)) SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    01026
    01027   if (v->breakdown_ctr != 0 || (v->vehstatus & VS_STOPPED) ||
    01028       _settings_game.difficulty.vehicle_breakdowns < 1 ||
    01029       v->cur_speed < 5 || _game_mode == GM_MENU) {
    01030     return;
    01031   }
    01032
    01033   uint32 r = Random();
    01034
    01035   /* increase chance of failure */
    01036   int chance = v->breakdown_chance + 1;
    01037   if (Chance16I(1, 25, r)) chance += 25;
    01038   v->breakdown_chance = min(255, chance);
    01039
    01040   /* calculate reliability value to use in comparison */
    01041   rel = v->reliability;
    01042   if (v->type == VEH_SHIP) rel += 0x6666;
    01043
    01044   /* reduced breakdowns? */
    01045   if (_settings_game.difficulty.vehicle_breakdowns == 1) rel += 0x6666;
    01046
    01047   /* check if to break down */
    01048   if (_breakdown_chance[(uint)min(rel, 0xffff) >> 10] <= v->breakdown_chance) {
    01049     v->breakdown_ctr    = GB(r, 16, 6) + 0x3F;
    01050     v->breakdown_delay  = GB(r, 24, 7) + 0x80;
    01051     v->breakdown_chance = 0;
    01052   }
    01053 }
    01054
    01061 bool Vehicle::HandleBreakdown()
    01062 {
    01063   /* Possible states for Vehicle::breakdown_ctr
    01064    * 0  - vehicle is running normally
    01065    * 1  - vehicle is currently broken down
    01066    * 2  - vehicle is going to break down now
    01067    * >2 - vehicle is counting down to the actual breakdown event */
    01068   switch (this->breakdown_ctr) {
    01069     case 0:
    01070       return false;
    01071
    01072     case 2:
    01073       this->breakdown_ctr = 1;
    01074
    01075       if (this->breakdowns_since_last_service != 255) {
    01076         this->breakdowns_since_last_service++;
    01077       }
    01078
    01079       this->MarkDirty();
    01080       SetWindowDirty(WC_VEHICLE_VIEW, this->index);
    01081       SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
    01082
    01083       if (this->type == VEH_AIRCRAFT) {
    01084         /* Aircraft just need this flag, the rest is handled elsewhere */
    01085         this->vehstatus |= VS_AIRCRAFT_BROKEN;
    01086       } else {
    01087         this->cur_speed = 0;
    01088
    01089         if (!PlayVehicleSound(this, VSE_BREAKDOWN)) {
    01090           SndPlayVehicleFx((_settings_game.game_creation.landscape != LT_TOYLAND) ?
    01091             (this->type == VEH_TRAIN ? SND_10_TRAIN_BREAKDOWN : SND_0F_VEHICLE_BREAKDOWN) :
    01092             (this->type == VEH_TRAIN ? SND_3A_COMEDY_BREAKDOWN_2 : SND_35_COMEDY_BREAKDOWN), this);
    01093         }
    01094
    01095         if (!(this->vehstatus & VS_HIDDEN)) {
    01096           EffectVehicle *u = CreateEffectVehicleRel(this, 4, 4, 5, EV_BREAKDOWN_SMOKE);
    01097           if (u != NULL) u->animation_state = this->breakdown_delay * 2;
    01098         }
    01099       }
    01100       /* FALL THROUGH */
    01101     case 1:
    01102       /* Aircraft breakdowns end only when arriving at the airport */
    01103       if (this->type == VEH_AIRCRAFT) return false;
    01104
    01105       /* For trains this function is called twice per tick, so decrease v->breakdown_delay at half the rate */
    01106       if ((this->tick_counter & (this->type == VEH_TRAIN ? 3 : 1)) == 0) {
    01107         if (--this->breakdown_delay == 0) {
    01108           this->breakdown_ctr = 0;
    01109           this->MarkDirty();
    01110           SetWindowDirty(WC_VEHICLE_VIEW, this->index);
    01111         }
    01112       }
    01113       return true;
    01114
    01115     default:
    01116       if (!this->current_order.IsType(OT_LOADING)) this->breakdown_ctr--;
    01117       return false;
    01118   }
    01119 }
    01120
    01125 void AgeVehicle(Vehicle *v)
    01126 {
    01127   if (v->age < MAX_DAY) v->age++;
    01128
    01129   int age = v->age - v->max_age;
    01130   if (age == DAYS_IN_LEAP_YEAR * 0 || age == DAYS_IN_LEAP_YEAR * 1 ||
    01131       age == DAYS_IN_LEAP_YEAR * 2 || age == DAYS_IN_LEAP_YEAR * 3 || age == DAYS_IN_LEAP_YEAR * 4) {
    01132     v->reliability_spd_dec <<= 1;
    01133   }
    01134
    01135   SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    01136
    01137   /* Don't warn about non-primary or not ours vehicles or vehicles that are crashed */
    01138   if (v->Previous() != NULL || v->owner != _local_company || (v->vehstatus & VS_CRASHED) != 0) return;
    01139
    01140   /* Don't warn if a renew is active */
    01141   if (Company::Get(v->owner)->settings.engine_renew && Engine::Get(v->engine_type)->company_avail != 0) return;
    01142
    01143   StringID str;
    01144   if (age == -DAYS_IN_LEAP_YEAR) {
    01145     str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
    01146   } else if (age == 0) {
    01147     str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
    01148   } else if (age > 0 && (age % DAYS_IN_LEAP_YEAR) == 0) {
    01149     str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
    01150   } else {
    01151     return;
    01152   }
    01153
    01154   SetDParam(0, v->index);
    01155   AddVehicleNewsItem(str, NS_ADVICE, v->index);
    01156 }
    01157
    01164 uint8 CalcPercentVehicleFilled(const Vehicle *v, StringID *colour)
    01165 {
    01166   int count = 0;
    01167   int max = 0;
    01168   int cars = 0;
    01169   int unloading = 0;
    01170   bool loading = false;
    01171
    01172   const Vehicle *u = v;
    01173   /* The station may be NULL when the (colour) string does not need to be set. */
    01174   const Station *st = Station::GetIfValid(v->last_station_visited);
    01175   assert(colour == NULL || st != NULL);
    01176
    01177   /* Count up max and used */
    01178   for (; v != NULL; v = v->Next()) {
    01179     count += v->cargo.Count();
    01180     max += v->cargo_cap;
    01181     if (v->cargo_cap != 0 && colour != NULL) {
    01182       unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0;
    01183       loading |= !(u->current_order.GetLoadType() & OLFB_NO_LOAD) && st->goods[v->cargo_type].days_since_pickup != 255;
    01184       cars++;
    01185     }
    01186   }
    01187
    01188   if (colour != NULL) {
    01189     if (unloading == 0 && loading) {
    01190       *colour = STR_PERCENT_UP;
    01191     } else if (cars == unloading || !loading) {
    01192       *colour = STR_PERCENT_DOWN;
    01193     } else {
    01194       *colour = STR_PERCENT_UP_DOWN;
    01195     }
    01196   }
    01197
    01198   /* Train without capacity */
    01199   if (max == 0) return 100;
    01200
    01201   /* Return the percentage */
    01202   return (count * 100) / max;
    01203 }
    01204
    01209 void VehicleEnterDepot(Vehicle *v)
    01210 {
    01211   /* Always work with the front of the vehicle */
    01212   assert(v == v->First());
    01213
    01214   switch (v->type) {
    01215     case VEH_TRAIN: {
    01216       Train *t = Train::From(v);
    01217       SetWindowClassesDirty(WC_TRAINS_LIST);
    01218       /* Clear path reservation */
    01219       SetDepotReservation(t->tile, false);
    01220       if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(t->tile);
    01221
    01222       UpdateSignalsOnSegment(t->tile, INVALID_DIAGDIR, t->owner);
    01223       t->wait_counter = 0;
    01224       t->force_proceed = TFP_NONE;
    01225       ClrBit(t->flags, VRF_TOGGLE_REVERSE);
    01226       t->ConsistChanged(true);
    01227       break;
    01228     }
    01229
    01230     case VEH_ROAD:
    01231       SetWindowClassesDirty(WC_ROADVEH_LIST);
    01232       break;
    01233
    01234     case VEH_SHIP: {
    01235       SetWindowClassesDirty(WC_SHIPS_LIST);
    01236       Ship *ship = Ship::From(v);
    01237       ship->state = TRACK_BIT_DEPOT;
    01238       ship->UpdateCache();
    01239       ship->UpdateViewport(true, true);
    01240       SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
    01241       break;
    01242     }
    01243
    01244     case VEH_AIRCRAFT:
    01245       SetWindowClassesDirty(WC_AIRCRAFT_LIST);
    01246       HandleAircraftEnterHangar(Aircraft::From(v));
    01247       break;
    01248     default: NOT_REACHED();
    01249   }
    01250   SetWindowDirty(WC_VEHICLE_VIEW, v->index);
    01251
    01252   if (v->type != VEH_TRAIN) {
    01253     /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
    01254      * 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 */
    01255     InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
    01256   }
    01257   SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
    01258
    01259   v->vehstatus |= VS_HIDDEN;
    01260   v->cur_speed = 0;
    01261
    01262   VehicleServiceInDepot(v);
    01263
    01264   TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
    01265
    01266   if (v->current_order.IsType(OT_GOTO_DEPOT)) {
    01267     SetWindowDirty(WC_VEHICLE_VIEW, v->index);
    01268
    01269     const Order *real_order = v->GetOrder(v->cur_real_order_index);
    01270     Order t = v->current_order;
    01271     v->current_order.MakeDummy();
    01272
    01273     /* Test whether we are heading for this depot. If not, do nothing.
    01274      * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
    01275     if ((t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) &&
    01276         real_order != NULL && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) &&
    01277         (v->type == VEH_AIRCRAFT ? t.GetDestination() != GetStationIndex(v->tile) : v->dest_tile != v->tile)) {
    01278       /* We are heading for another depot, keep driving. */
    01279       return;
    01280     }
    01281
    01282     if (t.IsRefit()) {
    01283       Backup<CompanyByte> cur_company(_current_company, v->owner, FILE_LINE);
    01284       CommandCost cost = DoCommand(v->tile, v->index, t.GetRefitCargo() | t.GetRefitSubtype() << 8, DC_EXEC, GetCmdRefitVeh(v));
    01285       cur_company.Restore();
    01286
    01287       if (cost.Failed()) {
    01288         _vehicles_to_autoreplace[v] = false;
    01289         if (v->owner == _local_company) {
    01290           /* Notify the user that we stopped the vehicle */
    01291           SetDParam(0, v->index);
    01292           AddVehicleNewsItem(STR_NEWS_ORDER_REFIT_FAILED, NS_ADVICE, v->index);
    01293         }
    01294       } else if (cost.GetCost() != 0) {
    01295         v->profit_this_year -= cost.GetCost() << 8;
    01296         if (v->owner == _local_company) {
    01297           ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
    01298         }
    01299       }
    01300     }
    01301
    01302     if (t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
    01303       /* Part of orders */
    01304       v->DeleteUnreachedAutoOrders();
    01305       UpdateVehicleTimetable(v, true);
    01306       v->IncrementAutoOrderIndex();
    01307     }
    01308     if (t.GetDepotActionType() & ODATFB_HALT) {
    01309       /* Vehicles are always stopped on entering depots. Do not restart this one. */
    01310       _vehicles_to_autoreplace[v] = false;
    01311       if (v->owner == _local_company) {
    01312         SetDParam(0, v->index);
    01313         AddVehicleNewsItem(STR_NEWS_TRAIN_IS_WAITING + v->type, NS_ADVICE, v->index);
    01314       }
    01315       AI::NewEvent(v->owner, new AIEventVehicleWaitingInDepot(v->index));
    01316     }
    01317   }
    01318 }
    01319
    01320
    01328 void VehicleMove(Vehicle *v, bool update_viewport)
    01329 {
    01330   int img = v->cur_image;
    01331   Point pt = RemapCoords(v->x_pos + v->x_offs, v->y_pos + v->y_offs, v->z_pos);
    01332   const Sprite *spr = GetSprite(img, ST_NORMAL);
    01333
    01334   pt.x += spr->x_offs;
    01335   pt.y += spr->y_offs;
    01336
    01337   UpdateVehiclePosHash(v, pt.x, pt.y);
    01338
    01339   Rect old_coord = v->coord;
    01340   v->coord.left   = pt.x;
    01341   v->coord.top    = pt.y;
    01342   v->coord.right  = pt.x + spr->width + 2;
    01343   v->coord.bottom = pt.y + spr->height + 2;
    01344
    01345   if (update_viewport) {
    01346     MarkAllViewportsDirty(
    01347       min(old_coord.left,   v->coord.left),
    01348       min(old_coord.top,    v->coord.top),
    01349       max(old_coord.right,  v->coord.right) + 1,
    01350       max(old_coord.bottom, v->coord.bottom) + 1
    01351     );
    01352   }
    01353 }
    01354
    01363 void MarkSingleVehicleDirty(const Vehicle *v)
    01364 {
    01365   MarkAllViewportsDirty(v->coord.left, v->coord.top, v->coord.right + 1, v->coord.bottom + 1);
    01366 }
    01367
    01373 GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
    01374 {
    01375   static const int8 _delta_coord[16] = {
    01376     -1,-1,-1, 0, 1, 1, 1, 0, /* x */
    01377     -1, 0, 1, 1, 1, 0,-1,-1, /* y */
    01378   };
    01379
    01380   int x = v->x_pos + _delta_coord[v->direction];
    01381   int y = v->y_pos + _delta_coord[v->direction + 8];
    01382
    01383   GetNewVehiclePosResult gp;
    01384   gp.x = x;
    01385   gp.y = y;
    01386   gp.old_tile = v->tile;
    01387   gp.new_tile = TileVirtXY(x, y);
    01388   return gp;
    01389 }
    01390
    01391 static const Direction _new_direction_table[] = {
    01392   DIR_N,  DIR_NW, DIR_W,
    01393   DIR_NE, DIR_SE, DIR_SW,
    01394   DIR_E,  DIR_SE, DIR_S
    01395 };
    01396
    01397 Direction GetDirectionTowards(const Vehicle *v, int x, int y)
    01398 {
    01399   int i = 0;
    01400
    01401   if (y >= v->y_pos) {
    01402     if (y != v->y_pos) i += 3;
    01403     i += 3;
    01404   }
    01405
    01406   if (x >= v->x_pos) {
    01407     if (x != v->x_pos) i++;
    01408     i++;
    01409   }
    01410
    01411   Direction dir = v->direction;
    01412
    01413   DirDiff dirdiff = DirDifference(_new_direction_table[i], dir);
    01414   if (dirdiff == DIRDIFF_SAME) return dir;
    01415   return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
    01416 }
    01417
    01427 VehicleEnterTileStatus VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
    01428 {
    01429   return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
    01430 }
    01431
    01439 FreeUnitIDGenerator::FreeUnitIDGenerator(VehicleType type, CompanyID owner) : cache(NULL), maxid(0), curid(0)
    01440 {
    01441   /* Find maximum */
    01442   const Vehicle *v;
    01443   FOR_ALL_VEHICLES(v) {
    01444     if (v->type == type && v->owner == owner) {
    01445       this->maxid = max<UnitID>(this->maxid, v->unitnumber);
    01446     }
    01447   }
    01448
    01449   if (this->maxid == 0) return;
    01450
    01451   /* Reserving 'maxid + 2' because we need:
    01452    * - space for the last item (with v->unitnumber == maxid)
    01453    * - one free slot working as loop terminator in FreeUnitIDGenerator::NextID() */
    01454   this->cache = CallocT<bool>(this->maxid + 2);
    01455
    01456   /* Fill the cache */
    01457   FOR_ALL_VEHICLES(v) {
    01458     if (v->type == type && v->owner == owner) {
    01459       this->cache[v->unitnumber] = true;
    01460     }
    01461   }
    01462 }
    01463
    01465 UnitID FreeUnitIDGenerator::NextID()
    01466 {
    01467   if (this->maxid <= this->curid) return ++this->curid;
    01468
    01469   while (this->cache[++this->curid]) { } // it will stop, we reserved more space than needed
    01470
    01471   return this->curid;
    01472 }
    01473
    01479 UnitID GetFreeUnitNumber(VehicleType type)
    01480 {
    01481   /* Check whether it is allowed to build another vehicle. */
    01482   uint max_veh;
    01483   switch (type) {
    01484     case VEH_TRAIN:    max_veh = _settings_game.vehicle.max_trains;   break;
    01485     case VEH_ROAD:     max_veh = _settings_game.vehicle.max_roadveh;  break;
    01486     case VEH_SHIP:     max_veh = _settings_game.vehicle.max_ships;    break;
    01487     case VEH_AIRCRAFT: max_veh = _settings_game.vehicle.max_aircraft; break;
    01488     default: NOT_REACHED();
    01489   }
    01490
    01491   uint amounts[4];
    01492   CountCompanyVehicles(_current_company, amounts);
    01493   assert((uint)type < lengthof(amounts));
    01494   if (amounts[type] >= max_veh) return UINT16_MAX; // Currently already at the limit, no room to make a new one.
    01495
    01496   FreeUnitIDGenerator gen(type, _current_company);
    01497
    01498   return gen.NextID();
    01499 }
    01500
    01501
    01510 bool CanBuildVehicleInfrastructure(VehicleType type)
    01511 {
    01512   assert(IsCompanyBuildableVehicleType(type));
    01513
    01514   if (!Company::IsValidID(_local_company)) return false;
    01515   if (!_settings_client.gui.disable_unsuitable_building) return true;
    01516
    01517   UnitID max;
    01518   switch (type) {
    01519     case VEH_TRAIN:    max = _settings_game.vehicle.max_trains; break;
    01520     case VEH_ROAD:     max = _settings_game.vehicle.max_roadveh; break;
    01521     case VEH_SHIP:     max = _settings_game.vehicle.max_ships; break;
    01522     case VEH_AIRCRAFT: max = _settings_game.vehicle.max_aircraft; break;
    01523     default: NOT_REACHED();
    01524   }
    01525
    01526   /* We can build vehicle infrastructure when we may build the vehicle type */
    01527   if (max > 0) {
    01528     /* Can we actually build the vehicle type? */
    01529     const Engine *e;
    01530     FOR_ALL_ENGINES_OF_TYPE(e, type) {
    01531       if (HasBit(e->company_avail, _local_company)) return true;
    01532     }
    01533     return false;
    01534   }
    01535
    01536   /* We should be able to build infrastructure when we have the actual vehicle type */
    01537   const Vehicle *v;
    01538   FOR_ALL_VEHICLES(v) {
    01539     if (v->owner == _local_company && v->type == type) return true;
    01540   }
    01541
    01542   return false;
    01543 }
    01544
    01545
    01553 LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
    01554 {
    01555   CargoID cargo_type = v == NULL ? (CargoID)CT_INVALID : v->cargo_type;
    01556   const Engine *e = Engine::Get(engine_type);
    01557   switch (e->type) {
    01558     default: NOT_REACHED();
    01559     case VEH_TRAIN:
    01560       if (v != NULL && parent_engine_type != INVALID_ENGINE && (UsesWagonOverride(v) || (v->IsArticulatedPart() && e->u.rail.railveh_type != RAILVEH_WAGON))) {
    01561         /* Wagonoverrides use the colour scheme of the front engine.
    01562          * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */
    01563         engine_type = parent_engine_type;
    01564         e = Engine::Get(engine_type);
    01565         /* Note: Luckily cargo_type is not needed for engines */
    01566       }
    01567
    01568       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01569       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01570       if (e->u.rail.railveh_type == RAILVEH_WAGON) {
    01571         if (!CargoSpec::Get(cargo_type)->is_freight) {
    01572           if (parent_engine_type == INVALID_ENGINE) {
    01573             return LS_PASSENGER_WAGON_STEAM;
    01574           } else {
    01575             switch (RailVehInfo(parent_engine_type)->engclass) {
    01576               default: NOT_REACHED();
    01577               case EC_STEAM:    return LS_PASSENGER_WAGON_STEAM;
    01578               case EC_DIESEL:   return LS_PASSENGER_WAGON_DIESEL;
    01579               case EC_ELECTRIC: return LS_PASSENGER_WAGON_ELECTRIC;
    01580               case EC_MONORAIL: return LS_PASSENGER_WAGON_MONORAIL;
    01581               case EC_MAGLEV:   return LS_PASSENGER_WAGON_MAGLEV;
    01582             }
    01583           }
    01584         } else {
    01585           return LS_FREIGHT_WAGON;
    01586         }
    01587       } else {
    01588         bool is_mu = HasBit(e->info.misc_flags, EF_RAIL_IS_MU);
    01589
    01590         switch (e->u.rail.engclass) {
    01591           default: NOT_REACHED();
    01592           case EC_STEAM:    return LS_STEAM;
    01593           case EC_DIESEL:   return is_mu ? LS_DMU : LS_DIESEL;
    01594           case EC_ELECTRIC: return is_mu ? LS_EMU : LS_ELECTRIC;
    01595           case EC_MONORAIL: return LS_MONORAIL;
    01596           case EC_MAGLEV:   return LS_MAGLEV;
    01597         }
    01598       }
    01599
    01600     case VEH_ROAD:
    01601       /* Always use the livery of the front */
    01602       if (v != NULL && parent_engine_type != INVALID_ENGINE) {
    01603         engine_type = parent_engine_type;
    01604         e = Engine::Get(engine_type);
    01605         cargo_type = v->First()->cargo_type;
    01606       }
    01607       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01608       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01609
    01610       /* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */
    01611       if (HasBit(e->info.misc_flags, EF_ROAD_TRAM)) {
    01612         /* Tram */
    01613         return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
    01614       } else {
    01615         /* Bus or truck */
    01616         return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_BUS : LS_TRUCK;
    01617       }
    01618
    01619     case VEH_SHIP:
    01620       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01621       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01622       return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
    01623
    01624     case VEH_AIRCRAFT:
    01625       switch (e->u.air.subtype) {
    01626         case AIR_HELI: return LS_HELICOPTER;
    01627         case AIR_CTOL: return LS_SMALL_PLANE;
    01628         case AIR_CTOL | AIR_FAST: return LS_LARGE_PLANE;
    01629         default: NOT_REACHED();
    01630       }
    01631   }
    01632 }
    01633
    01643 const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, byte livery_setting)
    01644 {
    01645   const Company *c = Company::Get(company);
    01646   LiveryScheme scheme = LS_DEFAULT;
    01647
    01648   /* The default livery is always available for use, but its in_use flag determines
    01649    * whether any _other_ liveries are in use. */
    01650   if (c->livery[LS_DEFAULT].in_use && (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company))) {
    01651     /* Determine the livery scheme to use */
    01652     scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
    01653
    01654     /* Switch back to the default scheme if the resolved scheme is not in use */
    01655     if (!c->livery[scheme].in_use) scheme = LS_DEFAULT;
    01656   }
    01657
    01658   return &c->livery[scheme];
    01659 }
    01660
    01661
    01662 static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
    01663 {
    01664   PaletteID map = (v != NULL) ? v->colourmap : PAL_NONE;
    01665
    01666   /* Return cached value if any */
    01667   if (map != PAL_NONE) return map;
    01668
    01669   const Engine *e = Engine::Get(engine_type);
    01670
    01671   /* Check if we should use the colour map callback */
    01672   if (HasBit(e->info.callback_mask, CBM_VEHICLE_COLOUR_REMAP)) {
    01673     uint16 callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
    01674     /* Failure means "use the default two-colour" */
    01675     if (callback != CALLBACK_FAILED) {
    01676       assert_compile(PAL_NONE == 0); // Returning 0x4000 (resp. 0xC000) conincidences with default value (PAL_NONE)
    01677       map = GB(callback, 0, 14);
    01678       /* If bit 14 is set, then the company colours are applied to the
    01679        * map else it's returned as-is. */
    01680       if (!HasBit(callback, 14)) {
    01681         /* Update cache */
    01682         if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
    01683         return map;
    01684       }
    01685     }
    01686   }
    01687
    01688   bool twocc = HasBit(e->info.misc_flags, EF_USES_2CC);
    01689
    01690   if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
    01691
    01692   /* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
    01693   if (!Company::IsValidID(company)) return map;
    01694
    01695   const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries);
    01696
    01697   map += livery->colour1;
    01698   if (twocc) map += livery->colour2 * 16;
    01699
    01700   /* Update cache */
    01701   if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
    01702   return map;
    01703 }
    01704
    01711 PaletteID GetEnginePalette(EngineID engine_type, CompanyID company)
    01712 {
    01713   return GetEngineColourMap(engine_type, company, INVALID_ENGINE, NULL);
    01714 }
    01715
    01721 PaletteID GetVehiclePalette(const Vehicle *v)
    01722 {
    01723   if (v->IsGroundVehicle()) {
    01724     return GetEngineColourMap(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v);
    01725   }
    01726
    01727   return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
    01728 }
    01729
    01738 uint GetVehicleCapacity(const Vehicle *v, uint16 *mail_capacity)
    01739 {
    01740   if (mail_capacity != NULL) *mail_capacity = 0;
    01741   const Engine *e = Engine::Get(v->engine_type);
    01742
    01743   if (!e->CanCarryCargo()) return 0;
    01744
    01745   if (mail_capacity != NULL && e->type == VEH_AIRCRAFT && IsCargoInClass(v->cargo_type, CC_PASSENGERS)) {
    01746     *mail_capacity = GetVehicleProperty(v, PROP_AIRCRAFT_MAIL_CAPACITY, e->u.air.mail_capacity);
    01747   }
    01748   CargoID default_cargo = e->GetDefaultCargoType();
    01749
    01750   /* Check the refit capacity callback if we are not in the default configuration.
    01751    * Note: This might change to become more consistent/flexible/sane, esp. when default cargo is first refittable. */
    01752   if (HasBit(e->info.callback_mask, CBM_VEHICLE_REFIT_CAPACITY) &&
    01753       (default_cargo != v->cargo_type || v->cargo_subtype != 0)) {
    01754     uint16 callback = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, v->engine_type, v);
    01755     if (callback != CALLBACK_FAILED) return callback;
    01756   }
    01757
    01758   /* Get capacity according to property resp. CB */
    01759   uint capacity;
    01760   switch (e->type) {
    01761     case VEH_TRAIN:    capacity = GetVehicleProperty(v, PROP_TRAIN_CARGO_CAPACITY,        e->u.rail.capacity); break;
    01762     case VEH_ROAD:     capacity = GetVehicleProperty(v, PROP_ROADVEH_CARGO_CAPACITY,      e->u.road.capacity); break;
    01763     case VEH_SHIP:     capacity = GetVehicleProperty(v, PROP_SHIP_CARGO_CAPACITY,         e->u.ship.capacity); break;
    01764     case VEH_AIRCRAFT: capacity = GetVehicleProperty(v, PROP_AIRCRAFT_PASSENGER_CAPACITY, e->u.air.passenger_capacity); break;
    01765     default: NOT_REACHED();
    01766   }
    01767
    01768   /* Apply multipliers depending on cargo- and vehicletype.
    01769    * Note: This might change to become more consistent/flexible. */
    01770   if (e->type != VEH_SHIP) {
    01771     if (e->type == VEH_AIRCRAFT) {
    01772       if (!IsCargoInClass(v->cargo_type, CC_PASSENGERS)) {
    01773         capacity += GetVehicleProperty(v, PROP_AIRCRAFT_MAIL_CAPACITY, e->u.air.mail_capacity);
    01774       }
    01775       if (v->cargo_type == CT_MAIL) return capacity;
    01776     } else {
    01777       switch (default_cargo) {
    01778         case CT_PASSENGERS: break;
    01779         case CT_MAIL:
    01780         case CT_GOODS: capacity *= 2; break;
    01781         default:       capacity *= 4; break;
    01782       }
    01783     }
    01784     switch (v->cargo_type) {
    01785       case CT_PASSENGERS: break;
    01786       case CT_MAIL:
    01787       case CT_GOODS: capacity /= 2; break;
    01788       default:       capacity /= 4; break;
    01789     }
    01790   }
    01791
    01792   return capacity;
    01793 }
    01794
    01798 void Vehicle::DeleteUnreachedAutoOrders()
    01799 {
    01800   const Order *order = this->GetOrder(this->cur_auto_order_index);
    01801   while (order != NULL) {
    01802     if (this->cur_auto_order_index == this->cur_real_order_index) break;
    01803
    01804     if (order->IsType(OT_AUTOMATIC)) {
    01805       /* Delete order effectively deletes order, so get the next before deleting it. */
    01806       order = order->next;
    01807       DeleteOrder(this, this->cur_auto_order_index);
    01808     } else {
    01809       /* Skip non-automatic orders, e.g. service-orders */
    01810       order = order->next;
    01811       this->cur_auto_order_index++;
    01812     }
    01813
    01814     /* Wrap around */
    01815     if (order == NULL) {
    01816       order = this->GetOrder(0);
    01817       this->cur_auto_order_index = 0;
    01818     }
    01819   }
    01820 }
    01821
    01826 void Vehicle::BeginLoading()
    01827 {
    01828   assert(IsTileType(this->tile, MP_STATION) || this->type == VEH_SHIP);
    01829
    01830   if (this->current_order.IsType(OT_GOTO_STATION) &&
    01831       this->current_order.GetDestination() == this->last_station_visited) {
    01832     this->DeleteUnreachedAutoOrders();
    01833
    01834     /* Now both order indices point to the destination station, and we can start loading */
    01835     this->current_order.MakeLoading(true);
    01836     UpdateVehicleTimetable(this, true);
    01837
    01838     /* Furthermore add the Non Stop flag to mark that this station
    01839      * is the actual destination of the vehicle, which is (for example)
    01840      * necessary to be known for HandleTrainLoading to determine
    01841      * whether the train is lost or not; not marking a train lost
    01842      * that arrives at random stations is bad. */
    01843     this->current_order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
    01844
    01845   } else {
    01846     /* We weren't scheduled to stop here. Insert an automatic order
    01847      * to show that we are stopping here, but only do that if the order
    01848      * list isn't empty. */
    01849     Order *in_list = this->GetOrder(this->cur_auto_order_index);
    01850     if (in_list != NULL && this->orders.list->GetNumOrders() < MAX_VEH_ORDER_ID &&
    01851         (!in_list->IsType(OT_AUTOMATIC) ||
    01852         in_list->GetDestination() != this->last_station_visited) &&
    01853         Order::CanAllocateItem()) {
    01854       Order *auto_order = new Order();
    01855       auto_order->MakeAutomatic(this->last_station_visited);
    01856       InsertOrder(this, auto_order, this->cur_auto_order_index);
    01857       if (this->cur_auto_order_index > 0) --this->cur_auto_order_index;
    01858     }
    01859     this->current_order.MakeLoading(false);
    01860   }
    01861
    01862   Station::Get(this->last_station_visited)->loading_vehicles.push_back(this);
    01863
    01864   PrepareUnload(this);
    01865
    01866   SetWindowDirty(GetWindowClassForVehicleType(this->type), this->owner);
    01867   SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    01868   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
    01869   SetWindowDirty(WC_STATION_VIEW, this->last_station_visited);
    01870
    01871   Station::Get(this->last_station_visited)->MarkTilesDirty(true);
    01872   this->cur_speed = 0;
    01873   this->MarkDirty();
    01874 }
    01875
    01880 void Vehicle::LeaveStation()
    01881 {
    01882   assert(this->current_order.IsType(OT_LOADING));
    01883
    01884   delete this->cargo_payment;
    01885
    01886   /* Only update the timetable if the vehicle was supposed to stop here. */
    01887   if (this->current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE) UpdateVehicleTimetable(this, false);
    01888
    01889   this->current_order.MakeLeaveStation();
    01890   Station *st = Station::Get(this->last_station_visited);
    01891   st->loading_vehicles.remove(this);
    01892
    01893   HideFillingPercent(&this->fill_percent_te_id);
    01894
    01895   if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) {
    01896     /* Trigger station animation (trains only) */
    01897     if (IsTileType(this->tile, MP_STATION)) TriggerStationAnimation(st, this->tile, SAT_TRAIN_DEPARTS);
    01898
    01899     SetBit(Train::From(this)->flags, VRF_LEAVING_STATION);
    01900   }
    01901 }
    01902
    01903
    01909 void Vehicle::HandleLoading(bool mode)
    01910 {
    01911   switch (this->current_order.GetType()) {
    01912     case OT_LOADING: {
    01913       uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0);
    01914
    01915       /* Not the first call for this tick, or still loading */
    01916       if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || this->current_order_time < wait_time) return;
    01917
    01918       this->PlayLeaveStationSound();
    01919
    01920       this->LeaveStation();
    01921
    01922       break;
    01923     }
    01924
    01925     case OT_DUMMY: break;
    01926
    01927     default: return;
    01928   }
    01929
    01930   this->IncrementAutoOrderIndex();
    01931 }
    01932
    01939 CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command)
    01940 {
    01941   CommandCost ret = CheckOwnership(this->owner);
    01942   if (ret.Failed()) return ret;
    01943
    01944   if (this->vehstatus & VS_CRASHED) return CMD_ERROR;
    01945   if (this->IsStoppedInDepot()) return CMD_ERROR;
    01946
    01947   if (this->current_order.IsType(OT_GOTO_DEPOT)) {
    01948     bool halt_in_depot = (this->current_order.GetDepotActionType() & ODATFB_HALT) != 0;
    01949     if (!!(command & DEPOT_SERVICE) == halt_in_depot) {
    01950       /* We called with a different DEPOT_SERVICE setting.
    01951        * Now we change the setting to apply the new one and let the vehicle head for the same depot.
    01952        * Note: the if is (true for requesting service == true for ordered to stop in depot)          */
    01953       if (flags & DC_EXEC) {
    01954         this->current_order.SetDepotOrderType(ODTF_MANUAL);
    01955         this->current_order.SetDepotActionType(halt_in_depot ? ODATF_SERVICE_ONLY : ODATFB_HALT);
    01956         SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    01957       }
    01958       return CommandCost();
    01959     }
    01960
    01961     if (command & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
    01962     if (flags & DC_EXEC) {
    01963       /* If the orders to 'goto depot' are in the orders list (forced servicing),
    01964        * then skip to the next order; effectively cancelling this forced service */
    01965       if (this->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) this->IncrementRealOrderIndex();
    01966
    01967       this->current_order.MakeDummy();
    01968       SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    01969     }
    01970     return CommandCost();
    01971   }
    01972
    01973   TileIndex location;
    01974   DestinationID destination;
    01975   bool reverse;
    01976   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};
    01977   if (!this->FindClosestDepot(&location, &destination, &reverse)) return_cmd_error(no_depot[this->type]);
    01978
    01979   if (flags & DC_EXEC) {
    01980     if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
    01981
    01982     this->dest_tile = location;
    01983     this->current_order.MakeGoToDepot(destination, ODTF_MANUAL);
    01984     if (!(command & DEPOT_SERVICE)) this->current_order.SetDepotActionType(ODATFB_HALT);
    01985     SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    01986
    01987     /* If there is no depot in front, reverse automatically (trains only) */
    01988     if (this->type == VEH_TRAIN && reverse) DoCommand(this->tile, this->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
    01989
    01990     if (this->type == VEH_AIRCRAFT) {
    01991       Aircraft *a = Aircraft::From(this);
    01992       if (a->state == FLYING && a->targetairport != destination) {
    01993         /* The aircraft is now heading for a different hangar than the next in the orders */
    01994         extern void AircraftNextAirportPos_and_Order(Aircraft *a);
    01995         AircraftNextAirportPos_and_Order(a);
    01996       }
    01997     }
    01998   }
    01999
    02000   return CommandCost();
    02001
    02002 }
    02003
    02008 void Vehicle::UpdateVisualEffect(bool allow_power_change)
    02009 {
    02010   bool powered_before = HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
    02011   const Engine *e = Engine::Get(this->engine_type);
    02012
    02013   /* Evaluate properties */
    02014   byte visual_effect;
    02015   switch (e->type) {
    02016     case VEH_TRAIN: visual_effect = e->u.rail.visual_effect; break;
    02017     case VEH_ROAD:  visual_effect = e->u.road.visual_effect; break;
    02018     case VEH_SHIP:  visual_effect = e->u.ship.visual_effect; break;
    02019     default:        visual_effect = 1 << VE_DISABLE_EFFECT;  break;
    02020   }
    02021
    02022   /* Check powered wagon / visual effect callback */
    02023   if (HasBit(e->info.callback_mask, CBM_VEHICLE_VISUAL_EFFECT)) {
    02024     uint16 callback = GetVehicleCallback(CBID_VEHICLE_VISUAL_EFFECT, 0, 0, this->engine_type, this);
    02025
    02026     if (callback != CALLBACK_FAILED) {
    02027       callback = GB(callback, 0, 8);
    02028       /* Avoid accidentally setting 'visual_effect' to the default value
    02029        * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
    02030       if (callback == VE_DEFAULT) {
    02031         assert(HasBit(callback, VE_DISABLE_EFFECT));
    02032         SB(callback, VE_TYPE_START, VE_TYPE_COUNT, 0);
    02033       }
    02034       visual_effect = callback;
    02035     }
    02036   }
    02037
    02038   /* Apply default values */
    02039   if (visual_effect == VE_DEFAULT ||
    02040       (!HasBit(visual_effect, VE_DISABLE_EFFECT) && GB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT) == VE_TYPE_DEFAULT)) {
    02041     /* Only train engines have default effects.
    02042      * Note: This is independent of whether the engine is a front engine or articulated part or whatever. */
    02043     if (e->type != VEH_TRAIN || e->u.rail.railveh_type == RAILVEH_WAGON || !IsInsideMM(e->u.rail.engclass, EC_STEAM, EC_MONORAIL)) {
    02044       if (visual_effect == VE_DEFAULT) {
    02045         visual_effect = 1 << VE_DISABLE_EFFECT;
    02046       } else {
    02047         SetBit(visual_effect, VE_DISABLE_EFFECT);
    02048       }
    02049     } else {
    02050       if (visual_effect == VE_DEFAULT) {
    02051         /* Also set the offset */
    02052         visual_effect = (VE_OFFSET_CENTRE - (e->u.rail.engclass == EC_STEAM ? 4 : 0)) << VE_OFFSET_START;
    02053       }
    02054       SB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT, e->u.rail.engclass - EC_STEAM + VE_TYPE_STEAM);
    02055     }
    02056   }
    02057
    02058   this->vcache.cached_vis_effect = visual_effect;
    02059
    02060   if (!allow_power_change && powered_before != HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
    02061     ToggleBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
    02062     ShowNewGrfVehicleError(this->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_POWERED_WAGON, GBUG_VEH_POWERED_WAGON, false);
    02063   }
    02064 }
    02065
    02066 static const int8 _vehicle_smoke_pos[8] = {
    02067   1, 1, 1, 0, -1, -1, -1, 0
    02068 };
    02069
    02074 void Vehicle::ShowVisualEffect() const
    02075 {
    02076   assert(this->IsPrimaryVehicle());
    02077   bool sound = false;
    02078
    02079   /* Do not show any smoke when:
    02080    * - vehicle smoke is disabled by the player
    02081    * - the vehicle is slowing down or stopped (by the player)
    02082    * - the vehicle is moving very slowly
    02083    */
    02084   if (_settings_game.vehicle.smoke_amount == 0 ||
    02085       this->vehstatus & (VS_TRAIN_SLOWING | VS_STOPPED) ||
    02086       this->cur_speed < 2) {
    02087     return;
    02088   }
    02089   if (this->type == VEH_TRAIN) {
    02090     const Train *t = Train::From(this);
    02091     /* For trains, do not show any smoke when:
    02092      * - the train is reversing
    02093      * - is entering a station with an order to stop there and its speed is equal to maximum station entering speed
    02094      */
    02095     if (HasBit(t->flags, VRF_REVERSING) ||
    02096         (IsRailStationTile(t->tile) && t->IsFrontEngine() && t->current_order.ShouldStopAtStation(t, GetStationIndex(t->tile)) &&
    02097         t->cur_speed >= t->Train::GetCurrentMaxSpeed())) {
    02098       return;
    02099     }
    02100   }
    02101
    02102   const Vehicle *v = this;
    02103
    02104   do {
    02105     int effect_offset = GB(v->vcache.cached_vis_effect, VE_OFFSET_START, VE_OFFSET_COUNT) - VE_OFFSET_CENTRE;
    02106     byte effect_type = GB(v->vcache.cached_vis_effect, VE_TYPE_START, VE_TYPE_COUNT);
    02107     bool disable_effect = HasBit(v->vcache.cached_vis_effect, VE_DISABLE_EFFECT);
    02108
    02109     /* Show no smoke when:
    02110      * - Smoke has been disabled for this vehicle
    02111      * - The vehicle is not visible
    02112      * - The vehicle is under a bridge
    02113      * - The vehicle is on a depot tile
    02114      * - The vehicle is on a tunnel tile
    02115      * - The vehicle is a train engine that is currently unpowered */
    02116     if (disable_effect ||
    02117         v->vehstatus & VS_HIDDEN ||
    02118         (MayHaveBridgeAbove(v->tile) && IsBridgeAbove(v->tile)) ||
    02119         IsDepotTile(v->tile) ||
    02120         IsTunnelTile(v->tile) ||
    02121         (v->type == VEH_TRAIN &&
    02122         !HasPowerOnRail(Train::From(v)->railtype, GetTileRailType(v->tile)))) {
    02123       continue;
    02124     }
    02125
    02126     int x = _vehicle_smoke_pos[v->direction] * effect_offset;
    02127     int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
    02128
    02129     if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) {
    02130       x = -x;
    02131       y = -y;
    02132     }
    02133
    02134     switch (effect_type) {
    02135       case VE_TYPE_STEAM:
    02136         /* Steam smoke - amount is gradually falling until vehicle reaches its maximum speed, after that it's normal.
    02137          * Details: while vehicle's current speed is gradually increasing, steam plumes' density decreases by one third each
    02138          * third of its maximum speed spectrum. Steam emission finally normalises at very close to vehicle's maximum speed.
    02139          * REGULATION:
    02140          * - instead of 1, 4 / 2^smoke_amount (max. 2) is used to provide sufficient regulation to steam puffs' amount. */
    02141         if (GB(v->tick_counter, 0, ((4 >> _settings_game.vehicle.smoke_amount) + ((this->cur_speed * 3) / this->vcache.cached_max_speed))) == 0) {
    02142           CreateEffectVehicleRel(v, x, y, 10, EV_STEAM_SMOKE);
    02143           sound = true;
    02144         }
    02145         break;
    02146
    02147       case VE_TYPE_DIESEL: {
    02148         /* Diesel smoke - thicker when vehicle is starting, gradually subsiding till it reaches its maximum speed
    02149          * when smoke emission stops.
    02150          * Details: Vehicle's (max.) speed spectrum is divided into 32 parts. When max. speed is reached, chance for smoke
    02151          * emission erodes by 32 (1/4). For trains, power and weight come in handy too to either increase smoke emission in
    02152          * 6 steps (1000HP each) if the power is low or decrease smoke emission in 6 steps (512 tonnes each) if the train
    02153          * isn't overweight. Power and weight contributions are expressed in a way that neither extreme power, nor
    02154          * extreme weight can ruin the balance (e.g. FreightWagonMultiplier) in the formula. When the vehicle reaches
    02155          * maximum speed no diesel_smoke is emitted.
    02156          * REGULATION:
    02157          * - up to which speed a diesel vehicle is emitting smoke (with reduced/small setting only until 1/2 of max_speed),
    02158          * - in Chance16 - the last value is 512 / 2^smoke_amount (max. smoke when 128 = smoke_amount of 2). */
    02159         int power_weight_effect = 0;
    02160         if (v->type == VEH_TRAIN) {
    02161           power_weight_effect = (32 >> (Train::From(this)->gcache.cached_power >> 10)) - (32 >> (Train::From(this)->gcache.cached_weight >> 9));
    02162         }
    02163         if (this->cur_speed < (this->vcache.cached_max_speed >> (2 >> _settings_game.vehicle.smoke_amount)) &&
    02164             Chance16((64 - ((this->cur_speed << 5) / this->vcache.cached_max_speed) + power_weight_effect), (512 >> _settings_game.vehicle.smoke_amount))) {
    02165           CreateEffectVehicleRel(v, x, y, 10, EV_DIESEL_SMOKE);
    02166           sound = true;
    02167         }
    02168         break;
    02169       }
    02170
    02171       case VE_TYPE_ELECTRIC:
    02172         /* Electric train's spark - more often occurs when train is departing (more load)
    02173          * Details: Electric locomotives are usually at least twice as powerful as their diesel counterparts, so spark
    02174          * emissions are kept simple. Only when starting, creating huge force are sparks more likely to happen, but when
    02175          * reaching its max. speed, quarter by quarter of it, chance decreases untill the usuall 2,22% at train's top speed.
    02176          * REGULATION:
    02177          * - in Chance16 the last value is 360 / 2^smoke_amount (max. sparks when 90 = smoke_amount of 2). */
    02178         if (GB(v->tick_counter, 0, 2) == 0 &&
    02179             Chance16((6 - ((this->cur_speed << 2) / this->vcache.cached_max_speed)), (360 >> _settings_game.vehicle.smoke_amount))) {
    02180           CreateEffectVehicleRel(v, x, y, 10, EV_ELECTRIC_SPARK);
    02181           sound = true;
    02182         }
    02183         break;
    02184
    02185       default:
    02186         break;
    02187     }
    02188   } while ((v = v->Next()) != NULL);
    02189
    02190   if (sound) PlayVehicleSound(this, VSE_VISUAL_EFFECT);
    02191 }
    02192
    02197 void Vehicle::SetNext(Vehicle *next)
    02198 {
    02199   assert(this != next);
    02200
    02201   if (this->next != NULL) {
    02202     /* We had an old next vehicle. Update the first and previous pointers */
    02203     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
    02204       v->first = this->next;
    02205     }
    02206     this->next->previous = NULL;
    02207   }
    02208
    02209   this->next = next;
    02210
    02211   if (this->next != NULL) {
    02212     /* A new next vehicle. Update the first and previous pointers */
    02213     if (this->next->previous != NULL) this->next->previous->next = NULL;
    02214     this->next->previous = this;
    02215     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
    02216       v->first = this->first;
    02217     }
    02218   }
    02219 }
    02220
    02226 void Vehicle::AddToShared(Vehicle *shared_chain)
    02227 {
    02228   assert(this->previous_shared == NULL && this->next_shared == NULL);
    02229
    02230   if (shared_chain->orders.list == NULL) {
    02231     assert(shared_chain->previous_shared == NULL);
    02232     assert(shared_chain->next_shared == NULL);
    02233     this->orders.list = shared_chain->orders.list = new OrderList(NULL, shared_chain);
    02234   }
    02235
    02236   this->next_shared     = shared_chain->next_shared;
    02237   this->previous_shared = shared_chain;
    02238
    02239   shared_chain->next_shared = this;
    02240
    02241   if (this->next_shared != NULL) this->next_shared->previous_shared = this;
    02242
    02243   shared_chain->orders.list->AddVehicle(this);
    02244 }
    02245
    02249 void Vehicle::RemoveFromShared()
    02250 {
    02251   /* Remember if we were first and the old window number before RemoveVehicle()
    02252    * as this changes first if needed. */
    02253   bool were_first = (this->FirstShared() == this);
    02254   VehicleListIdentifier vli(VL_SHARED_ORDERS, this->type, this->owner, this->FirstShared()->index);
    02255
    02256   this->orders.list->RemoveVehicle(this);
    02257
    02258   if (!were_first) {
    02259     /* We are not the first shared one, so only relink our previous one. */
    02260     this->previous_shared->next_shared = this->NextShared();
    02261   }
    02262
    02263   if (this->next_shared != NULL) this->next_shared->previous_shared = this->previous_shared;
    02264
    02265
    02266   if (this->orders.list->GetNumVehicles() == 1) {
    02267     /* When there is only one vehicle, remove the shared order list window. */
    02268     DeleteWindowById(GetWindowClassForVehicleType(this->type), vli.Pack());
    02269     InvalidateVehicleOrder(this->FirstShared(), 0);
    02270   } else if (were_first) {
    02271     /* If we were the first one, update to the new first one.
    02272      * Note: FirstShared() is already the new first */
    02273     InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.Pack(), this->FirstShared()->index | (1U << 31), true);
    02274   }
    02275
    02276   this->next_shared     = NULL;
    02277   this->previous_shared = NULL;
    02278 }
    02279
    02280 void VehiclesYearlyLoop()
    02281 {
    02282   Vehicle *v;
    02283   FOR_ALL_VEHICLES(v) {
    02284     if (v->IsPrimaryVehicle()) {
    02285       /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
    02286       Money profit = v->GetDisplayProfitThisYear();
    02287       if (v->age >= 730 && profit < 0) {
    02288         if (_settings_client.gui.vehicle_income_warn && v->owner == _local_company) {
    02289           SetDParam(0, v->index);
    02290           SetDParam(1, profit);
    02291           AddVehicleNewsItem(
    02292             STR_NEWS_VEHICLE_IS_UNPROFITABLE,
    02293             NS_ADVICE,
    02294             v->index
    02295           );
    02296         }
    02297         AI::NewEvent(v->owner, new AIEventVehicleUnprofitable(v->index));
    02298       }
    02299
    02300       v->profit_last_year = v->profit_this_year;
    02301       v->profit_this_year = 0;
    02302       SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    02303     }
    02304   }
    02305 }
    02306
    02307
    02317 bool CanVehicleUseStation(EngineID engine_type, const Station *st)
    02318 {
    02319   const Engine *e = Engine::GetIfValid(engine_type);
    02320   assert(e != NULL);
    02321
    02322   switch (e->type) {
    02323     case VEH_TRAIN:
    02324       return (st->facilities & FACIL_TRAIN) != 0;
    02325
    02326     case VEH_ROAD:
    02327       /* For road vehicles we need the vehicle to know whether it can actually
    02328        * use the station, but if it doesn't have facilities for RVs it is
    02329        * certainly not possible that the station can be used. */
    02330       return (st->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP)) != 0;
    02331
    02332     case VEH_SHIP:
    02333       return (st->facilities & FACIL_DOCK) != 0;
    02334
    02335     case VEH_AIRCRAFT:
    02336       return (st->facilities & FACIL_AIRPORT) != 0 &&
    02337           (st->airport.GetFTA()->flags & (e->u.air.subtype & AIR_CTOL ? AirportFTAClass::AIRPLANES : AirportFTAClass::HELICOPTERS)) != 0;
    02338
    02339     default:
    02340       return false;
    02341   }
    02342 }
    02343
    02350 bool CanVehicleUseStation(const Vehicle *v, const Station *st)
    02351 {
    02352   if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != NULL;
    02353
    02354   return CanVehicleUseStation(v->engine_type, st);
    02355 }
    02356
    02362 GroundVehicleCache *Vehicle::GetGroundVehicleCache()
    02363 {
    02364   assert(this->IsGroundVehicle());
    02365   if (this->type == VEH_TRAIN) {
    02366     return &Train::From(this)->gcache;
    02367   } else {
    02368     return &RoadVehicle::From(this)->gcache;
    02369   }
    02370 }
    02371
    02377 const GroundVehicleCache *Vehicle::GetGroundVehicleCache() const
    02378 {
    02379   assert(this->IsGroundVehicle());
    02380   if (this->type == VEH_TRAIN) {
    02381     return &Train::From(this)->gcache;
    02382   } else {
    02383     return &RoadVehicle::From(this)->gcache;
    02384   }
    02385 }
    02386
    02395 void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8 num_vehicles)
    02396 {
    02397   if (v->type == VEH_TRAIN) {
    02398     Train *u = Train::From(v);
    02399     /* Only include whole vehicles, so start with the first articulated part */
    02400     u = u->GetFirstEnginePart();
    02401
    02402     /* Include num_vehicles vehicles, not counting articulated parts */
    02403     for (; u != NULL && num_vehicles > 0; num_vehicles--) {
    02404       do {
    02405         /* Include current vehicle in the selection. */
    02406         set.Include(u->index);
    02407
    02408         /* If the vehicle is multiheaded, add the other part too. */
    02409         if (u->IsMultiheaded()) set.Include(u->other_multiheaded_part->index);
    02410
    02411         u = u->Next();
    02412       } while (u != NULL && u->IsArticulatedPart());
    02413     }
    02414   }
    02415 }