# vehicle.cpp

Go to the documentation of this file.

    00001 /* $Id: vehicle.cpp 25986 2013-11-13 21:49:31Z 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 "error.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 "train.h"
    00023 #include "aircraft.h"
    00024 #include "newgrf_debug.h"
    00025 #include "newgrf_sound.h"
    00026 #include "newgrf_station.h"
    00027 #include "group_gui.h"
    00028 #include "strings_func.h"
    00029 #include "zoom_func.h"
    00030 #include "date_func.h"
    00031 #include "vehicle_func.h"
    00032 #include "autoreplace_func.h"
    00033 #include "autoreplace_gui.h"
    00034 #include "station_base.h"
    00035 #include "ai/ai.hpp"
    00036 #include "depot_func.h"
    00037 #include "network/network.h"
    00038 #include "core/pool_func.hpp"
    00039 #include "economy_base.h"
    00040 #include "articulated_vehicles.h"
    00041 #include "roadstop_base.h"
    00042 #include "core/random_func.hpp"
    00043 #include "core/backup_type.hpp"
    00044 #include "order_backup.h"
    00045 #include "sound_func.h"
    00046 #include "effectvehicle_func.h"
    00047 #include "effectvehicle_base.h"
    00048 #include "vehiclelist.h"
    00049 #include "bridge_map.h"
    00050 #include "tunnel_map.h"
    00051 #include "depot_map.h"
    00052 #include "gamelog.h"
    00053
    00054 #include "table/strings.h"
    00055
    00056 #define GEN_HASH(x, y) ((GB((y), 6 + ZOOM_LVL_SHIFT, 6) << 6) + GB((x), 7 + ZOOM_LVL_SHIFT, 6))
    00057
    00058 VehicleID _new_vehicle_id;
    00059 uint16 _returned_refit_capacity;
    00060 uint16 _returned_mail_refit_capacity;
    00061
    00062
    00064 VehiclePool _vehicle_pool("Vehicle");
    00065 INSTANTIATE_POOL_METHODS(Vehicle)
    00066
    00067
    00073 bool Vehicle::NeedsAutorenewing(const Company *c, bool use_renew_setting) const
    00074 {
    00075   /* We can always generate the Company pointer when we have the vehicle.
    00076    * However this takes time and since the Company pointer is often present
    00077    * when this function is called then it's faster to pass the pointer as an
    00078    * argument rather than finding it again. */
    00079   assert(c == Company::Get(this->owner));
    00080
    00081   if (use_renew_setting && !c->settings.engine_renew) return false;
    00082   if (this->age - this->max_age < (c->settings.engine_renew_months * 30)) return false;
    00083
    00084   /* Only engines need renewing */
    00085   if (this->type == VEH_TRAIN && !Train::From(this)->IsEngine()) return false;
    00086
    00087   return true;
    00088 }
    00089
    00095 void VehicleServiceInDepot(Vehicle *v)
    00096 {
    00097   assert(v != NULL);
    00098   SetWindowDirty(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
    00099
    00100   do {
    00101     v->date_of_last_service = _date;
    00102     v->breakdowns_since_last_service = 0;
    00103     v->reliability = v->GetEngine()->reliability;
    00104     /* Prevent vehicles from breaking down directly after exiting the depot. */
    00105     v->breakdown_chance /= 4;
    00106     v = v->Next();
    00107   } while (v != NULL && v->HasEngineType());
    00108 }
    00109
    00116 bool Vehicle::NeedsServicing() const
    00117 {
    00118   /* Stopped or crashed vehicles will not move, as such making unmovable
    00119    * vehicles to go for service is lame. */
    00120   if (this->vehstatus & (VS_STOPPED | VS_CRASHED)) return false;
    00121
    00122   /* Are we ready for the next service cycle? */
    00123   const Company *c = Company::Get(this->owner);
    00124   if (this->ServiceIntervalIsPercent() ?
    00125       (this->reliability >= this->GetEngine()->reliability * (100 - this->GetServiceInterval()) / 100) :
    00126       (this->date_of_last_service + this->GetServiceInterval() >= _date)) {
    00127     return false;
    00128   }
    00129
    00130   /* If we're servicing anyway, because we have not disabled servicing when
    00131    * there are no breakdowns or we are playing with breakdowns, bail out. */
    00132   if (!_settings_game.order.no_servicing_if_no_breakdowns ||
    00133       _settings_game.difficulty.vehicle_breakdowns != 0) {
    00134     return true;
    00135   }
    00136
    00137   /* Test whether there is some pending autoreplace.
    00138    * Note: We do this after the service-interval test.
    00139    * There are a lot more reasons for autoreplace to fail than we can test here reasonably. */
    00140   bool pending_replace = false;
    00141   Money needed_money = c->settings.engine_renew_money;
    00142   if (needed_money > c->money) return false;
    00143
    00144   for (const Vehicle *v = this; v != NULL; v = (v->type == VEH_TRAIN) ? Train::From(v)->GetNextUnit() : NULL) {
    00145     bool replace_when_old = false;
    00146     EngineID new_engine = EngineReplacementForCompany(c, v->engine_type, v->group_id, &replace_when_old);
    00147
    00148     /* Check engine availability */
    00149     if (new_engine == INVALID_ENGINE || !HasBit(Engine::Get(new_engine)->company_avail, v->owner)) continue;
    00150     /* Is the vehicle old if we are not always replacing? */
    00151     if (replace_when_old && !v->NeedsAutorenewing(c, false)) continue;
    00152
    00153     /* Check refittability */
    00154     uint32 available_cargo_types, union_mask;
    00155     GetArticulatedRefitMasks(new_engine, true, &union_mask, &available_cargo_types);
    00156     /* Is there anything to refit? */
    00157     if (union_mask != 0) {
    00158       CargoID cargo_type;
    00159       /* We cannot refit to mixed cargoes in an automated way */
    00160       if (IsArticulatedVehicleCarryingDifferentCargoes(v, &cargo_type)) continue;
    00161
    00162       /* Did the old vehicle carry anything? */
    00163       if (cargo_type != CT_INVALID) {
    00164         /* We can't refit the vehicle to carry the cargo we want */
    00165         if (!HasBit(available_cargo_types, cargo_type)) continue;
    00166       }
    00167     }
    00168
    00169     /* Check money.
    00170      * We want 2*(the price of the new vehicle) without looking at the value of the vehicle we are going to sell. */
    00171     pending_replace = true;
    00172     needed_money += 2 * Engine::Get(new_engine)->GetCost();
    00173     if (needed_money > c->money) return false;
    00174   }
    00175
    00176   return pending_replace;
    00177 }
    00178
    00184 bool Vehicle::NeedsAutomaticServicing() const
    00185 {
    00186   if (this->HasDepotOrder()) return false;
    00187   if (this->current_order.IsType(OT_LOADING)) return false;
    00188   if (this->current_order.IsType(OT_GOTO_DEPOT) && this->current_order.GetDepotOrderType() != ODTFB_SERVICE) return false;
    00189   return NeedsServicing();
    00190 }
    00191
    00192 uint Vehicle::Crash(bool flooded)
    00193 {
    00194   assert((this->vehstatus & VS_CRASHED) == 0);
    00195   assert(this->Previous() == NULL); // IsPrimaryVehicle fails for free-wagon-chains
    00196
    00197   uint pass = 0;
    00198   /* Stop the vehicle. */
    00199   if (this->IsPrimaryVehicle()) this->vehstatus |= VS_STOPPED;
    00200   /* crash all wagons, and count passengers */
    00201   for (Vehicle *v = this; v != NULL; v = v->Next()) {
    00202     if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) pass += v->cargo.Count();
    00203     v->vehstatus |= VS_CRASHED;
    00204     MarkSingleVehicleDirty(v);
    00205   }
    00206
    00207   /* Dirty some windows */
    00208   InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
    00209   SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
    00210   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
    00211   SetWindowDirty(WC_VEHICLE_DEPOT, this->tile);
    00212
    00213   delete this->cargo_payment;
    00214   this->cargo_payment = NULL;
    00215
    00216   return RandomRange(pass + 1); // Randomise deceased passengers.
    00217 }
    00218
    00219
    00228 void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical)
    00229 {
    00230   const Engine *e = Engine::Get(engine);
    00231   GRFConfig *grfconfig = GetGRFConfig(e->GetGRFID());
    00232
    00233   if (!HasBit(grfconfig->grf_bugs, bug_type)) {
    00234     SetBit(grfconfig->grf_bugs, bug_type);
    00235     SetDParamStr(0, grfconfig->GetName());
    00236     SetDParam(1, engine);
    00237     ShowErrorMessage(part1, part2, WL_CRITICAL);
    00238     if (!_networking) DoCommand(0, critical ? PM_PAUSED_ERROR : PM_PAUSED_NORMAL, 1, DC_EXEC, CMD_PAUSE);
    00239   }
    00240
    00241   /* debug output */
    00242   char buffer[512];
    00243
    00244   SetDParamStr(0, grfconfig->GetName());
    00245   GetString(buffer, part1, lastof(buffer));
    00246   DEBUG(grf, 0, "%s", buffer + 3);
    00247
    00248   SetDParam(1, engine);
    00249   GetString(buffer, part2, lastof(buffer));
    00250   DEBUG(grf, 0, "%s", buffer + 3);
    00251 }
    00252
    00258 void VehicleLengthChanged(const Vehicle *u)
    00259 {
    00260   /* show a warning once for each engine in whole game and once for each GRF after each game load */
    00261   const Engine *engine = u->GetEngine();
    00262   uint32 grfid = engine->grf_prop.grffile->grfid;
    00263   GRFConfig *grfconfig = GetGRFConfig(grfid);
    00264   if (GamelogGRFBugReverse(grfid, engine->grf_prop.local_id) || !HasBit(grfconfig->grf_bugs, GBUG_VEH_LENGTH)) {
    00265     ShowNewGrfVehicleError(u->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_VEHICLE_LENGTH, GBUG_VEH_LENGTH, true);
    00266   }
    00267 }
    00268
    00273 Vehicle::Vehicle(VehicleType type)
    00274 {
    00275   this->type               = type;
    00276   this->coord.left         = INVALID_COORD;
    00277   this->group_id           = DEFAULT_GROUP;
    00278   this->fill_percent_te_id = INVALID_TE_ID;
    00279   this->first              = this;
    00280   this->colourmap          = PAL_NONE;
    00281   this->cargo_age_counter  = 1;
    00282 }
    00283
    00288 byte VehicleRandomBits()
    00289 {
    00290   return GB(Random(), 0, 8);
    00291 }
    00292
    00293 /* Size of the hash, 6 = 64 x 64, 7 = 128 x 128. Larger sizes will (in theory) reduce hash
    00294  * lookup times at the expense of memory usage. */
    00295 const int HASH_BITS = 7;
    00296 const int HASH_SIZE = 1 << HASH_BITS;
    00297 const int HASH_MASK = HASH_SIZE - 1;
    00298 const int TOTAL_HASH_SIZE = 1 << (HASH_BITS * 2);
    00299 const int TOTAL_HASH_MASK = TOTAL_HASH_SIZE - 1;
    00300
    00301 /* Resolution of the hash, 0 = 1*1 tile, 1 = 2*2 tiles, 2 = 4*4 tiles, etc.
    00302  * Profiling results show that 0 is fastest. */
    00303 const int HASH_RES = 0;
    00304
    00305 static Vehicle *_vehicle_tile_hash[TOTAL_HASH_SIZE];
    00306
    00307 static Vehicle *VehicleFromTileHash(int xl, int yl, int xu, int yu, void *data, VehicleFromPosProc *proc, bool find_first)
    00308 {
    00309   for (int y = yl; ; y = (y + (1 << HASH_BITS)) & (HASH_MASK << HASH_BITS)) {
    00310     for (int x = xl; ; x = (x + 1) & HASH_MASK) {
    00311       Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
    00312       for (; v != NULL; v = v->hash_tile_next) {
    00313         Vehicle *a = proc(v, data);
    00314         if (find_first && a != NULL) return a;
    00315       }
    00316       if (x == xu) break;
    00317     }
    00318     if (y == yu) break;
    00319   }
    00320
    00321   return NULL;
    00322 }
    00323
    00324
    00336 static Vehicle *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc, bool find_first)
    00337 {
    00338   const int COLL_DIST = 6;
    00339
    00340   /* Hash area to scan is from xl,yl to xu,yu */
    00341   int xl = GB((x - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
    00342   int xu = GB((x + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
    00343   int yl = GB((y - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
    00344   int yu = GB((y + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
    00345
    00346   return VehicleFromTileHash(xl, yl, xu, yu, data, proc, find_first);
    00347 }
    00348
    00363 void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
    00364 {
    00365   VehicleFromPosXY(x, y, data, proc, false);
    00366 }
    00367
    00379 bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
    00380 {
    00381   return VehicleFromPosXY(x, y, data, proc, true) != NULL;
    00382 }
    00383
    00394 static Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc, bool find_first)
    00395 {
    00396   int x = GB(TileX(tile), HASH_RES, HASH_BITS);
    00397   int y = GB(TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS;
    00398
    00399   Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
    00400   for (; v != NULL; v = v->hash_tile_next) {
    00401     if (v->tile != tile) continue;
    00402
    00403     Vehicle *a = proc(v, data);
    00404     if (find_first && a != NULL) return a;
    00405   }
    00406
    00407   return NULL;
    00408 }
    00409
    00423 void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
    00424 {
    00425   VehicleFromPos(tile, data, proc, false);
    00426 }
    00427
    00438 bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
    00439 {
    00440   return VehicleFromPos(tile, data, proc, true) != NULL;
    00441 }
    00442
    00449 static Vehicle *EnsureNoVehicleProcZ(Vehicle *v, void *data)
    00450 {
    00451   int z = *(int*)data;
    00452
    00453   if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
    00454   if (v->z_pos > z) return NULL;
    00455
    00456   return v;
    00457 }
    00458
    00464 CommandCost EnsureNoVehicleOnGround(TileIndex tile)
    00465 {
    00466   int z = GetTileMaxPixelZ(tile);
    00467
    00468   /* Value v is not safe in MP games, however, it is used to generate a local
    00469    * error message only (which may be different for different machines).
    00470    * Such a message does not affect MP synchronisation.
    00471    */
    00472   Vehicle *v = VehicleFromPos(tile, &z, &EnsureNoVehicleProcZ, true);
    00473   if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
    00474   return CommandCost();
    00475 }
    00476
    00478 static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
    00479 {
    00480   if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) return NULL;
    00481   if (v == (const Vehicle *)data) return NULL;
    00482
    00483   return v;
    00484 }
    00485
    00493 CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore)
    00494 {
    00495   /* Value v is not safe in MP games, however, it is used to generate a local
    00496    * error message only (which may be different for different machines).
    00497    * Such a message does not affect MP synchronisation.
    00498    */
    00499   Vehicle *v = VehicleFromPos(tile, const_cast<Vehicle *>(ignore), &GetVehicleTunnelBridgeProc, true);
    00500   if (v == NULL) v = VehicleFromPos(endtile, const_cast<Vehicle *>(ignore), &GetVehicleTunnelBridgeProc, true);
    00501
    00502   if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
    00503   return CommandCost();
    00504 }
    00505
    00506 static Vehicle *EnsureNoTrainOnTrackProc(Vehicle *v, void *data)
    00507 {
    00508   TrackBits rail_bits = *(TrackBits *)data;
    00509
    00510   if (v->type != VEH_TRAIN) return NULL;
    00511
    00512   Train *t = Train::From(v);
    00513   if ((t->track != rail_bits) && !TracksOverlap(t->track | rail_bits)) return NULL;
    00514
    00515   return v;
    00516 }
    00517
    00526 CommandCost EnsureNoTrainOnTrackBits(TileIndex tile, TrackBits track_bits)
    00527 {
    00528   /* Value v is not safe in MP games, however, it is used to generate a local
    00529    * error message only (which may be different for different machines).
    00530    * Such a message does not affect MP synchronisation.
    00531    */
    00532   Vehicle *v = VehicleFromPos(tile, &track_bits, &EnsureNoTrainOnTrackProc, true);
    00533   if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
    00534   return CommandCost();
    00535 }
    00536
    00537 static void UpdateVehicleTileHash(Vehicle *v, bool remove)
    00538 {
    00539   Vehicle **old_hash = v->hash_tile_current;
    00540   Vehicle **new_hash;
    00541
    00542   if (remove) {
    00543     new_hash = NULL;
    00544   } else {
    00545     int x = GB(TileX(v->tile), HASH_RES, HASH_BITS);
    00546     int y = GB(TileY(v->tile), HASH_RES, HASH_BITS) << HASH_BITS;
    00547     new_hash = &_vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK];
    00548   }
    00549
    00550   if (old_hash == new_hash) return;
    00551
    00552   /* Remove from the old position in the hash table */
    00553   if (old_hash != NULL) {
    00554     if (v->hash_tile_next != NULL) v->hash_tile_next->hash_tile_prev = v->hash_tile_prev;
    00555     *v->hash_tile_prev = v->hash_tile_next;
    00556   }
    00557
    00558   /* Insert vehicle at beginning of the new position in the hash table */
    00559   if (new_hash != NULL) {
    00560     v->hash_tile_next = *new_hash;
    00561     if (v->hash_tile_next != NULL) v->hash_tile_next->hash_tile_prev = &v->hash_tile_next;
    00562     v->hash_tile_prev = new_hash;
    00563     *new_hash = v;
    00564   }
    00565
    00566   /* Remember current hash position */
    00567   v->hash_tile_current = new_hash;
    00568 }
    00569
    00570 static Vehicle *_vehicle_viewport_hash[0x1000];
    00571
    00572 static void UpdateVehicleViewportHash(Vehicle *v, int x, int y)
    00573 {
    00574   Vehicle **old_hash, **new_hash;
    00575   int old_x = v->coord.left;
    00576   int old_y = v->coord.top;
    00577
    00578   new_hash = (x == INVALID_COORD) ? NULL : &_vehicle_viewport_hash[GEN_HASH(x, y)];
    00579   old_hash = (old_x == INVALID_COORD) ? NULL : &_vehicle_viewport_hash[GEN_HASH(old_x, old_y)];
    00580
    00581   if (old_hash == new_hash) return;
    00582
    00583   /* remove from hash table? */
    00584   if (old_hash != NULL) {
    00585     if (v->hash_viewport_next != NULL) v->hash_viewport_next->hash_viewport_prev = v->hash_viewport_prev;
    00586     *v->hash_viewport_prev = v->hash_viewport_next;
    00587   }
    00588
    00589   /* insert into hash table? */
    00590   if (new_hash != NULL) {
    00591     v->hash_viewport_next = *new_hash;
    00592     if (v->hash_viewport_next != NULL) v->hash_viewport_next->hash_viewport_prev = &v->hash_viewport_next;
    00593     v->hash_viewport_prev = new_hash;
    00594     *new_hash = v;
    00595   }
    00596 }
    00597
    00598 void ResetVehicleHash()
    00599 {
    00600   Vehicle *v;
    00601   FOR_ALL_VEHICLES(v) { v->hash_tile_current = NULL; }
    00602   memset(_vehicle_viewport_hash, 0, sizeof(_vehicle_viewport_hash));
    00603   memset(_vehicle_tile_hash, 0, sizeof(_vehicle_tile_hash));
    00604 }
    00605
    00606 void ResetVehicleColourMap()
    00607 {
    00608   Vehicle *v;
    00609   FOR_ALL_VEHICLES(v) { v->colourmap = PAL_NONE; }
    00610 }
    00611
    00616 typedef SmallMap<Vehicle *, bool, 4> AutoreplaceMap;
    00617 static AutoreplaceMap _vehicles_to_autoreplace;
    00618
    00619 void InitializeVehicles()
    00620 {
    00621   _vehicles_to_autoreplace.Reset();
    00622   ResetVehicleHash();
    00623 }
    00624
    00625 uint CountVehiclesInChain(const Vehicle *v)
    00626 {
    00627   uint count = 0;
    00628   do count++; while ((v = v->Next()) != NULL);
    00629   return count;
    00630 }
    00631
    00636 bool Vehicle::IsEngineCountable() const
    00637 {
    00638   switch (this->type) {
    00639     case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft(); // don't count plane shadows and helicopter rotors
    00640     case VEH_TRAIN:
    00641       return !this->IsArticulatedPart() && // tenders and other articulated parts
    00642           !Train::From(this)->IsRearDualheaded(); // rear parts of multiheaded engines
    00643     case VEH_ROAD: return RoadVehicle::From(this)->IsFrontEngine();
    00644     case VEH_SHIP: return true;
    00645     default: return false; // Only count company buildable vehicles
    00646   }
    00647 }
    00648
    00653 bool Vehicle::HasEngineType() const
    00654 {
    00655   switch (this->type) {
    00656     case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft();
    00657     case VEH_TRAIN:
    00658     case VEH_ROAD:
    00659     case VEH_SHIP: return true;
    00660     default: return false;
    00661   }
    00662 }
    00663
    00669 const Engine *Vehicle::GetEngine() const
    00670 {
    00671   return Engine::Get(this->engine_type);
    00672 }
    00673
    00679 const GRFFile *Vehicle::GetGRF() const
    00680 {
    00681   return this->GetEngine()->GetGRF();
    00682 }
    00683
    00689 uint32 Vehicle::GetGRFID() const
    00690 {
    00691   return this->GetEngine()->GetGRFID();
    00692 }
    00693
    00701 void Vehicle::HandlePathfindingResult(bool path_found)
    00702 {
    00703   if (path_found) {
    00704     /* Route found, is the vehicle marked with "lost" flag? */
    00705     if (!HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;
    00706
    00707     /* Clear the flag as the PF's problem was solved. */
    00708     ClrBit(this->vehicle_flags, VF_PATHFINDER_LOST);
    00709     /* Delete the news item. */
    00710     DeleteVehicleNews(this->index, STR_NEWS_VEHICLE_IS_LOST);
    00711     return;
    00712   }
    00713
    00714   /* Were we already lost? */
    00715   if (HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;
    00716
    00717   /* It is first time the problem occurred, set the "lost" flag. */
    00718   SetBit(this->vehicle_flags, VF_PATHFINDER_LOST);
    00719   /* Notify user about the event. */
    00720   AI::NewEvent(this->owner, new ScriptEventVehicleLost(this->index));
    00721   if (_settings_client.gui.lost_vehicle_warn && this->owner == _local_company) {
    00722     SetDParam(0, this->index);
    00723     AddVehicleAdviceNewsItem(STR_NEWS_VEHICLE_IS_LOST, this->index);
    00724   }
    00725 }
    00726
    00728 void Vehicle::PreDestructor()
    00729 {
    00730   if (CleaningPool()) return;
    00731
    00732   if (Station::IsValidID(this->last_station_visited)) {
    00733     Station::Get(this->last_station_visited)->loading_vehicles.remove(this);
    00734
    00735     HideFillingPercent(&this->fill_percent_te_id);
    00736
    00737     delete this->cargo_payment;
    00738   }
    00739
    00740   if (this->IsEngineCountable()) {
    00741     GroupStatistics::CountEngine(this, -1);
    00742     if (this->IsPrimaryVehicle()) GroupStatistics::CountVehicle(this, -1);
    00743     GroupStatistics::UpdateAutoreplace(this->owner);
    00744
    00745     if (this->owner == _local_company) InvalidateAutoreplaceWindow(this->engine_type, this->group_id);
    00746     DeleteGroupHighlightOfVehicle(this);
    00747   }
    00748
    00749   if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) {
    00750     Aircraft *a = Aircraft::From(this);
    00751     Station *st = GetTargetAirportIfValid(a);
    00752     if (st != NULL) {
    00753       const AirportFTA *layout = st->airport.GetFTA()->layout;
    00754       CLRBITS(st->airport.flags, layout[a->previous_pos].block | layout[a->pos].block);
    00755     }
    00756   }
    00757
    00758
    00759   if (this->type == VEH_ROAD && this->IsPrimaryVehicle()) {
    00760     RoadVehicle *v = RoadVehicle::From(this);
    00761     if (!(v->vehstatus & VS_CRASHED) && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
    00762       /* Leave the drive through roadstop, when you have not already left it. */
    00763       RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
    00764     }
    00765   }
    00766
    00767   if (this->Previous() == NULL) {
    00768     InvalidateWindowData(WC_VEHICLE_DEPOT, this->tile);
    00769   }
    00770
    00771   if (this->IsPrimaryVehicle()) {
    00772     DeleteWindowById(WC_VEHICLE_VIEW, this->index);
    00773     DeleteWindowById(WC_VEHICLE_ORDERS, this->index);
    00774     DeleteWindowById(WC_VEHICLE_REFIT, this->index);
    00775     DeleteWindowById(WC_VEHICLE_DETAILS, this->index);
    00776     DeleteWindowById(WC_VEHICLE_TIMETABLE, this->index);
    00777     SetWindowDirty(WC_COMPANY, this->owner);
    00778     OrderBackup::ClearVehicle(this);
    00779   }
    00780   InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
    00781
    00782   this->cargo.Truncate(0);
    00783   DeleteVehicleOrders(this);
    00784   DeleteDepotHighlightOfVehicle(this);
    00785
    00786   extern void StopGlobalFollowVehicle(const Vehicle *v);
    00787   StopGlobalFollowVehicle(this);
    00788
    00789   ReleaseDisastersTargetingVehicle(this->index);
    00790 }
    00791
    00792 Vehicle::~Vehicle()
    00793 {
    00794   if (CleaningPool()) {
    00795     this->cargo.OnCleanPool();
    00796     return;
    00797   }
    00798
    00799   /* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles,
    00800    * it may happen that vehicle chain is deleted when visible */
    00801   if (!(this->vehstatus & VS_HIDDEN)) MarkSingleVehicleDirty(this);
    00802
    00803   Vehicle *v = this->Next();
    00804   this->SetNext(NULL);
    00805
    00806   delete v;
    00807
    00808   UpdateVehicleTileHash(this, true);
    00809   UpdateVehicleViewportHash(this, INVALID_COORD, 0);
    00810   DeleteVehicleNews(this->index, INVALID_STRING_ID);
    00811   DeleteNewGRFInspectWindow(GetGrfSpecFeature(this->type), this->index);
    00812 }
    00813
    00818 void VehicleEnteredDepotThisTick(Vehicle *v)
    00819 {
    00820   /* Vehicle should stop in the depot if it was in 'stopping' state */
    00821   _vehicles_to_autoreplace[v] = !(v->vehstatus & VS_STOPPED);
    00822
    00823   /* We ALWAYS set the stopped state. Even when the vehicle does not plan on
    00824    * stopping in the depot, so we stop it to ensure that it will not reserve
    00825    * the path out of the depot before we might autoreplace it to a different
    00826    * engine. The new engine would not own the reserved path we store that we
    00827    * stopped the vehicle, so autoreplace can start it again */
    00828   v->vehstatus |= VS_STOPPED;
    00829 }
    00830
    00836 static void RunVehicleDayProc()
    00837 {
    00838   if (_game_mode != GM_NORMAL) return;
    00839
    00840   /* Run the day_proc for every DAY_TICKS vehicle starting at _date_fract. */
    00841   for (size_t i = _date_fract; i < Vehicle::GetPoolSize(); i += DAY_TICKS) {
    00842     Vehicle *v = Vehicle::Get(i);
    00843     if (v == NULL) continue;
    00844
    00845     /* Call the 32-day callback if needed */
    00846     if ((v->day_counter & 0x1F) == 0 && v->HasEngineType()) {
    00847       uint16 callback = GetVehicleCallback(CBID_VEHICLE_32DAY_CALLBACK, 0, 0, v->engine_type, v);
    00848       if (callback != CALLBACK_FAILED) {
    00849         if (HasBit(callback, 0)) {
    00850           /* After a vehicle trigger, the graphics and properties of the vehicle could change. */
    00851           TriggerVehicle(v, VEHICLE_TRIGGER_CALLBACK_32); // Trigger vehicle trigger 10
    00852           v->First()->MarkDirty();
    00853         }
    00854         if (HasBit(callback, 1)) v->colourmap = PAL_NONE;
    00855
    00856         if (callback & ~3) ErrorUnknownCallbackResult(v->GetGRFID(), CBID_VEHICLE_32DAY_CALLBACK, callback);
    00857       }
    00858     }
    00859
    00860     /* This is called once per day for each vehicle, but not in the first tick of the day */
    00861     v->OnNewDay();
    00862   }
    00863 }
    00864
    00865 void CallVehicleTicks()
    00866 {
    00867   _vehicles_to_autoreplace.Clear();
    00868
    00869   RunVehicleDayProc();
    00870
    00871   Station *st;
    00872   FOR_ALL_STATIONS(st) LoadUnloadStation(st);
    00873
    00874   Vehicle *v;
    00875   FOR_ALL_VEHICLES(v) {
    00876     /* Vehicle could be deleted in this tick */
    00877     if (!v->Tick()) {
    00878       assert(Vehicle::Get(vehicle_index) == NULL);
    00879       continue;
    00880     }
    00881
    00882     assert(Vehicle::Get(vehicle_index) == v);
    00883
    00884     switch (v->type) {
    00885       default: break;
    00886
    00887       case VEH_TRAIN:
    00888       case VEH_ROAD:
    00889       case VEH_AIRCRAFT:
    00890       case VEH_SHIP: {
    00891         Vehicle *front = v->First();
    00892
    00893         if (v->vcache.cached_cargo_age_period != 0) {
    00894           v->cargo_age_counter = min(v->cargo_age_counter, v->vcache.cached_cargo_age_period);
    00895           if (--v->cargo_age_counter == 0) {
    00896             v->cargo.AgeCargo();
    00897             v->cargo_age_counter = v->vcache.cached_cargo_age_period;
    00898           }
    00899         }
    00900
    00901         /* Do not play any sound when crashed */
    00902         if (front->vehstatus & VS_CRASHED) continue;
    00903
    00904         /* Do not play any sound when in depot or tunnel */
    00905         if (v->vehstatus & VS_HIDDEN) continue;
    00906
    00907         /* Do not play any sound when stopped */
    00908         if ((front->vehstatus & VS_STOPPED) && (front->type != VEH_TRAIN || front->cur_speed == 0)) continue;
    00909
    00910         /* Check vehicle type specifics */
    00911         switch (v->type) {
    00912           case VEH_TRAIN:
    00913             if (Train::From(v)->IsWagon()) continue;
    00914             break;
    00915
    00916           case VEH_ROAD:
    00917             if (!RoadVehicle::From(v)->IsFrontEngine()) continue;
    00918             break;
    00919
    00920           case VEH_AIRCRAFT:
    00921             if (!Aircraft::From(v)->IsNormalAircraft()) continue;
    00922             break;
    00923
    00924           default:
    00925             break;
    00926         }
    00927
    00928         v->motion_counter += front->cur_speed;
    00929         /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
    00930         if (GB(v->motion_counter, 0, 8) < front->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
    00931
    00932         /* Play an alternating running sound every 16 ticks */
    00933         if (GB(v->tick_counter, 0, 4) == 0) {
    00934           /* Play running sound when speed > 0 and not braking */
    00935           bool running = (front->cur_speed > 0) && !(front->vehstatus & (VS_STOPPED | VS_TRAIN_SLOWING));
    00936           PlayVehicleSound(v, running ? VSE_RUNNING_16 : VSE_STOPPED_16);
    00937         }
    00938
    00939         break;
    00940       }
    00941     }
    00942   }
    00943
    00944   Backup<CompanyByte> cur_company(_current_company, FILE_LINE);
    00945   for (AutoreplaceMap::iterator it = _vehicles_to_autoreplace.Begin(); it != _vehicles_to_autoreplace.End(); it++) {
    00946     v = it->first;
    00947     /* Autoreplace needs the current company set as the vehicle owner */
    00948     cur_company.Change(v->owner);
    00949
    00950     /* Start vehicle if we stopped them in VehicleEnteredDepotThisTick()
    00951      * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that
    00952      * they are already leaving the depot again before being replaced. */
    00953     if (it->second) v->vehstatus &= ~VS_STOPPED;
    00954
    00955     /* Store the position of the effect as the vehicle pointer will become invalid later */
    00956     int x = v->x_pos;
    00957     int y = v->y_pos;
    00958     int z = v->z_pos;
    00959
    00960     const Company *c = Company::Get(_current_company);
    00961     SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, (Money)c->settings.engine_renew_money));
    00962     CommandCost res = DoCommand(0, v->index, 0, DC_EXEC, CMD_AUTOREPLACE_VEHICLE);
    00963     SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, -(Money)c->settings.engine_renew_money));
    00964
    00965     if (!IsLocalCompany()) continue;
    00966
    00967     if (res.Succeeded()) {
    00968       ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
    00969       continue;
    00970     }
    00971
    00972     StringID error_message = res.GetErrorMessage();
    00973     if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message == INVALID_STRING_ID) continue;
    00974
    00975     if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT;
    00976
    00977     StringID message;
    00978     if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
    00979       message = error_message;
    00980     } else {
    00981       message = STR_NEWS_VEHICLE_AUTORENEW_FAILED;
    00982     }
    00983
    00984     SetDParam(0, v->index);
    00985     SetDParam(1, error_message);
    00986     AddVehicleAdviceNewsItem(message, v->index);
    00987   }
    00988
    00989   cur_company.Restore();
    00990 }
    00991
    00996 static void DoDrawVehicle(const Vehicle *v)
    00997 {
    00998   SpriteID image = v->cur_image;
    00999   PaletteID pal = PAL_NONE;
    01000
    01001   if (v->vehstatus & VS_DEFPAL) pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
    01002
    01003   /* Check whether the vehicle shall be transparent due to the game state */
    01004   bool shadowed = (v->vehstatus & VS_SHADOW) != 0;
    01005
    01006   if (v->type == VEH_EFFECT) {
    01007     /* Check whether the vehicle shall be transparent/invisible due to GUI settings.
    01008      * However, transparent smoke and bubbles look weird, so always hide them. */
    01009     TransparencyOption to = EffectVehicle::From(v)->GetTransparencyOption();
    01010     if (to != TO_INVALID && (IsTransparencySet(to) || IsInvisibilitySet(to))) return;
    01011   }
    01012
    01013   AddSortableSpriteToDraw(image, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
    01014     v->x_extent, v->y_extent, v->z_extent, v->z_pos, shadowed, v->x_bb_offs, v->y_bb_offs);
    01015 }
    01016
    01021 void ViewportAddVehicles(DrawPixelInfo *dpi)
    01022 {
    01023   /* The bounding rectangle */
    01024   const int l = dpi->left;
    01025   const int r = dpi->left + dpi->width;
    01026   const int t = dpi->top;
    01027   const int b = dpi->top + dpi->height;
    01028
    01029   /* The hash area to scan */
    01030   int xl, xu, yl, yu;
    01031
    01032   if (dpi->width + (70 * ZOOM_LVL_BASE) < (1 << (7 + 6 + ZOOM_LVL_SHIFT))) {
    01033     xl = GB(l - (70 * ZOOM_LVL_BASE), 7 + ZOOM_LVL_SHIFT, 6);
    01034     xu = GB(r,                        7 + ZOOM_LVL_SHIFT, 6);
    01035   } else {
    01036     /* scan whole hash row */
    01037     xl = 0;
    01038     xu = 0x3F;
    01039   }
    01040
    01041   if (dpi->height + (70 * ZOOM_LVL_BASE) < (1 << (6 + 6 + ZOOM_LVL_SHIFT))) {
    01042     yl = GB(t - (70 * ZOOM_LVL_BASE), 6 + ZOOM_LVL_SHIFT, 6) << 6;
    01043     yu = GB(b,                        6 + ZOOM_LVL_SHIFT, 6) << 6;
    01044   } else {
    01045     /* scan whole column */
    01046     yl = 0;
    01047     yu = 0x3F << 6;
    01048   }
    01049
    01050   for (int y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
    01051     for (int x = xl;; x = (x + 1) & 0x3F) {
    01052       const Vehicle *v = _vehicle_viewport_hash[x + y]; // already masked & 0xFFF
    01053
    01054       while (v != NULL) {
    01055         if (!(v->vehstatus & VS_HIDDEN) &&
    01056             l <= v->coord.right &&
    01057             t <= v->coord.bottom &&
    01058             r >= v->coord.left &&
    01059             b >= v->coord.top) {
    01060           DoDrawVehicle(v);
    01061         }
    01062         v = v->hash_viewport_next;
    01063       }
    01064
    01065       if (x == xu) break;
    01066     }
    01067
    01068     if (y == yu) break;
    01069   }
    01070 }
    01071
    01079 Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y)
    01080 {
    01081   Vehicle *found = NULL, *v;
    01082   uint dist, best_dist = UINT_MAX;
    01083
    01084   if ((uint)(x -= vp->left) >= (uint)vp->width || (uint)(y -= vp->top) >= (uint)vp->height) return NULL;
    01085
    01086   x = ScaleByZoom(x, vp->zoom) + vp->virtual_left;
    01087   y = ScaleByZoom(y, vp->zoom) + vp->virtual_top;
    01088
    01089   FOR_ALL_VEHICLES(v) {
    01090     if ((v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0 &&
    01091         x >= v->coord.left && x <= v->coord.right &&
    01092         y >= v->coord.top && y <= v->coord.bottom) {
    01093
    01094       dist = max(
    01095         abs(((v->coord.left + v->coord.right) >> 1) - x),
    01096         abs(((v->coord.top + v->coord.bottom) >> 1) - y)
    01097       );
    01098
    01099       if (dist < best_dist) {
    01100         found = v;
    01101         best_dist = dist;
    01102       }
    01103     }
    01104   }
    01105
    01106   return found;
    01107 }
    01108
    01113 void DecreaseVehicleValue(Vehicle *v)
    01114 {
    01115   v->value -= v->value >> 8;
    01116   SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    01117 }
    01118
    01119 static const byte _breakdown_chance[64] = {
    01120     3,   3,   3,   3,   3,   3,   3,   3,
    01121     4,   4,   5,   5,   6,   6,   7,   7,
    01122     8,   8,   9,   9,  10,  10,  11,  11,
    01123    12,  13,  13,  13,  13,  14,  15,  16,
    01124    17,  19,  21,  25,  28,  31,  34,  37,
    01125    40,  44,  48,  52,  56,  60,  64,  68,
    01126    72,  80,  90, 100, 110, 120, 130, 140,
    01127   150, 170, 190, 210, 230, 250, 250, 250,
    01128 };
    01129
    01130 void CheckVehicleBreakdown(Vehicle *v)
    01131 {
    01132   int rel, rel_old;
    01133
    01134   /* decrease reliability */
    01135   v->reliability = rel = max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
    01136   if ((rel_old >> 8) != (rel >> 8)) SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    01137
    01138   if (v->breakdown_ctr != 0 || (v->vehstatus & VS_STOPPED) ||
    01139       _settings_game.difficulty.vehicle_breakdowns < 1 ||
    01140       v->cur_speed < 5 || _game_mode == GM_MENU) {
    01141     return;
    01142   }
    01143
    01144   uint32 r = Random();
    01145
    01146   /* increase chance of failure */
    01147   int chance = v->breakdown_chance + 1;
    01148   if (Chance16I(1, 25, r)) chance += 25;
    01149   v->breakdown_chance = min(255, chance);
    01150
    01151   /* calculate reliability value to use in comparison */
    01152   rel = v->reliability;
    01153   if (v->type == VEH_SHIP) rel += 0x6666;
    01154
    01155   /* reduced breakdowns? */
    01156   if (_settings_game.difficulty.vehicle_breakdowns == 1) rel += 0x6666;
    01157
    01158   /* check if to break down */
    01159   if (_breakdown_chance[(uint)min(rel, 0xffff) >> 10] <= v->breakdown_chance) {
    01160     v->breakdown_ctr    = GB(r, 16, 6) + 0x3F;
    01161     v->breakdown_delay  = GB(r, 24, 7) + 0x80;
    01162     v->breakdown_chance = 0;
    01163   }
    01164 }
    01165
    01172 bool Vehicle::HandleBreakdown()
    01173 {
    01174   /* Possible states for Vehicle::breakdown_ctr
    01175    * 0  - vehicle is running normally
    01176    * 1  - vehicle is currently broken down
    01177    * 2  - vehicle is going to break down now
    01178    * >2 - vehicle is counting down to the actual breakdown event */
    01179   switch (this->breakdown_ctr) {
    01180     case 0:
    01181       return false;
    01182
    01183     case 2:
    01184       this->breakdown_ctr = 1;
    01185
    01186       if (this->breakdowns_since_last_service != 255) {
    01187         this->breakdowns_since_last_service++;
    01188       }
    01189
    01190       if (this->type == VEH_AIRCRAFT) {
    01191         /* Aircraft just need this flag, the rest is handled elsewhere */
    01192         this->vehstatus |= VS_AIRCRAFT_BROKEN;
    01193       } else {
    01194         this->cur_speed = 0;
    01195
    01196         if (!PlayVehicleSound(this, VSE_BREAKDOWN)) {
    01197           SndPlayVehicleFx((_settings_game.game_creation.landscape != LT_TOYLAND) ?
    01198             (this->type == VEH_TRAIN ? SND_10_TRAIN_BREAKDOWN : SND_0F_VEHICLE_BREAKDOWN) :
    01199             (this->type == VEH_TRAIN ? SND_3A_COMEDY_BREAKDOWN_2 : SND_35_COMEDY_BREAKDOWN), this);
    01200         }
    01201
    01202         if (!(this->vehstatus & VS_HIDDEN) && !HasBit(EngInfo(this->engine_type)->misc_flags, EF_NO_BREAKDOWN_SMOKE)) {
    01203           EffectVehicle *u = CreateEffectVehicleRel(this, 4, 4, 5, EV_BREAKDOWN_SMOKE);
    01204           if (u != NULL) u->animation_state = this->breakdown_delay * 2;
    01205         }
    01206       }
    01207
    01208       this->MarkDirty(); // Update graphics after speed is zeroed
    01209       SetWindowDirty(WC_VEHICLE_VIEW, this->index);
    01210       SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
    01211
    01212       /* FALL THROUGH */
    01213     case 1:
    01214       /* Aircraft breakdowns end only when arriving at the airport */
    01215       if (this->type == VEH_AIRCRAFT) return false;
    01216
    01217       /* For trains this function is called twice per tick, so decrease v->breakdown_delay at half the rate */
    01218       if ((this->tick_counter & (this->type == VEH_TRAIN ? 3 : 1)) == 0) {
    01219         if (--this->breakdown_delay == 0) {
    01220           this->breakdown_ctr = 0;
    01221           this->MarkDirty();
    01222           SetWindowDirty(WC_VEHICLE_VIEW, this->index);
    01223         }
    01224       }
    01225       return true;
    01226
    01227     default:
    01228       if (!this->current_order.IsType(OT_LOADING)) this->breakdown_ctr--;
    01229       return false;
    01230   }
    01231 }
    01232
    01237 void AgeVehicle(Vehicle *v)
    01238 {
    01239   if (v->age < MAX_DAY) {
    01240     v->age++;
    01241     if (v->IsPrimaryVehicle() && v->age == VEHICLE_PROFIT_MIN_AGE + 1) GroupStatistics::VehicleReachedProfitAge(v);
    01242   }
    01243
    01244   if (!v->IsPrimaryVehicle() && (v->type != VEH_TRAIN || !Train::From(v)->IsEngine())) return;
    01245
    01246   int age = v->age - v->max_age;
    01247   if (age == DAYS_IN_LEAP_YEAR * 0 || age == DAYS_IN_LEAP_YEAR * 1 ||
    01248       age == DAYS_IN_LEAP_YEAR * 2 || age == DAYS_IN_LEAP_YEAR * 3 || age == DAYS_IN_LEAP_YEAR * 4) {
    01249     v->reliability_spd_dec <<= 1;
    01250   }
    01251
    01252   SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    01253
    01254   /* Don't warn about non-primary or not ours vehicles or vehicles that are crashed */
    01255   if (v->Previous() != NULL || v->owner != _local_company || (v->vehstatus & VS_CRASHED) != 0) return;
    01256
    01257   /* Don't warn if a renew is active */
    01258   if (Company::Get(v->owner)->settings.engine_renew && v->GetEngine()->company_avail != 0) return;
    01259
    01260   StringID str;
    01261   if (age == -DAYS_IN_LEAP_YEAR) {
    01262     str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
    01263   } else if (age == 0) {
    01264     str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
    01265   } else if (age > 0 && (age % DAYS_IN_LEAP_YEAR) == 0) {
    01266     str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
    01267   } else {
    01268     return;
    01269   }
    01270
    01271   SetDParam(0, v->index);
    01272   AddVehicleAdviceNewsItem(str, v->index);
    01273 }
    01274
    01281 uint8 CalcPercentVehicleFilled(const Vehicle *front, StringID *colour)
    01282 {
    01283   int count = 0;
    01284   int max = 0;
    01285   int cars = 0;
    01286   int unloading = 0;
    01287   bool loading = false;
    01288
    01289   bool is_loading = front->current_order.IsType(OT_LOADING);
    01290
    01291   /* The station may be NULL when the (colour) string does not need to be set. */
    01292   const Station *st = Station::GetIfValid(front->last_station_visited);
    01293   assert(colour == NULL || (st != NULL && is_loading));
    01294
    01295   bool order_no_load = is_loading && (front->current_order.GetLoadType() & OLFB_NO_LOAD);
    01296   bool order_full_load = is_loading && (front->current_order.GetLoadType() & OLFB_FULL_LOAD);
    01297
    01298   /* Count up max and used */
    01299   for (const Vehicle *v = front; v != NULL; v = v->Next()) {
    01300     count += v->cargo.Count();
    01301     max += v->cargo_cap;
    01302     if (v->cargo_cap != 0 && colour != NULL) {
    01303       unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0;
    01304       loading |= !order_no_load &&
    01305           (order_full_load || HasBit(st->goods[v->cargo_type].acceptance_pickup, GoodsEntry::GES_PICKUP)) &&
    01306           !HasBit(v->vehicle_flags, VF_LOADING_FINISHED) && !HasBit(v->vehicle_flags, VF_STOP_LOADING);
    01307       cars++;
    01308     }
    01309   }
    01310
    01311   if (colour != NULL) {
    01312     if (unloading == 0 && loading) {
    01313       *colour = STR_PERCENT_UP;
    01314     } else if (unloading == 0 && !loading) {
    01315       *colour = STR_PERCENT_NONE;
    01316     } else if (cars == unloading || !loading) {
    01317       *colour = STR_PERCENT_DOWN;
    01318     } else {
    01319       *colour = STR_PERCENT_UP_DOWN;
    01320     }
    01321   }
    01322
    01323   /* Train without capacity */
    01324   if (max == 0) return 100;
    01325
    01326   /* Return the percentage */
    01327   return (count * 100) / max;
    01328 }
    01329
    01334 void VehicleEnterDepot(Vehicle *v)
    01335 {
    01336   /* Always work with the front of the vehicle */
    01337   assert(v == v->First());
    01338
    01339   switch (v->type) {
    01340     case VEH_TRAIN: {
    01341       Train *t = Train::From(v);
    01342       SetWindowClassesDirty(WC_TRAINS_LIST);
    01343       /* Clear path reservation */
    01344       SetDepotReservation(t->tile, false);
    01345       if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(t->tile);
    01346
    01347       UpdateSignalsOnSegment(t->tile, INVALID_DIAGDIR, t->owner);
    01348       t->wait_counter = 0;
    01349       t->force_proceed = TFP_NONE;
    01350       ClrBit(t->flags, VRF_TOGGLE_REVERSE);
    01351       t->ConsistChanged(true);
    01352       break;
    01353     }
    01354
    01355     case VEH_ROAD:
    01356       SetWindowClassesDirty(WC_ROADVEH_LIST);
    01357       break;
    01358
    01359     case VEH_SHIP: {
    01360       SetWindowClassesDirty(WC_SHIPS_LIST);
    01361       Ship *ship = Ship::From(v);
    01362       ship->state = TRACK_BIT_DEPOT;
    01363       ship->UpdateCache();
    01364       ship->UpdateViewport(true, true);
    01365       SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
    01366       break;
    01367     }
    01368
    01369     case VEH_AIRCRAFT:
    01370       SetWindowClassesDirty(WC_AIRCRAFT_LIST);
    01371       HandleAircraftEnterHangar(Aircraft::From(v));
    01372       break;
    01373     default: NOT_REACHED();
    01374   }
    01375   SetWindowDirty(WC_VEHICLE_VIEW, v->index);
    01376
    01377   if (v->type != VEH_TRAIN) {
    01378     /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
    01379      * 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 */
    01380     InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
    01381   }
    01382   SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
    01383
    01384   v->vehstatus |= VS_HIDDEN;
    01385   v->cur_speed = 0;
    01386
    01387   VehicleServiceInDepot(v);
    01388
    01389   /* After a vehicle trigger, the graphics and properties of the vehicle could change. */
    01390   TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
    01391   v->MarkDirty();
    01392
    01393   if (v->current_order.IsType(OT_GOTO_DEPOT)) {
    01394     SetWindowDirty(WC_VEHICLE_VIEW, v->index);
    01395
    01396     const Order *real_order = v->GetOrder(v->cur_real_order_index);
    01397     Order t = v->current_order;
    01398     v->current_order.MakeDummy();
    01399
    01400     /* Test whether we are heading for this depot. If not, do nothing.
    01401      * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
    01402     if ((t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) &&
    01403         real_order != NULL && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) &&
    01404         (v->type == VEH_AIRCRAFT ? t.GetDestination() != GetStationIndex(v->tile) : v->dest_tile != v->tile)) {
    01405       /* We are heading for another depot, keep driving. */
    01406       return;
    01407     }
    01408
    01409     if (t.IsRefit()) {
    01410       Backup<CompanyByte> cur_company(_current_company, v->owner, FILE_LINE);
    01411       CommandCost cost = DoCommand(v->tile, v->index, t.GetRefitCargo() | t.GetRefitSubtype() << 8, DC_EXEC, GetCmdRefitVeh(v));
    01412       cur_company.Restore();
    01413
    01414       if (cost.Failed()) {
    01415         _vehicles_to_autoreplace[v] = false;
    01416         if (v->owner == _local_company) {
    01417           /* Notify the user that we stopped the vehicle */
    01418           SetDParam(0, v->index);
    01419           AddVehicleAdviceNewsItem(STR_NEWS_ORDER_REFIT_FAILED, v->index);
    01420         }
    01421       } else if (cost.GetCost() != 0) {
    01422         v->profit_this_year -= cost.GetCost() << 8;
    01423         if (v->owner == _local_company) {
    01424           ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
    01425         }
    01426       }
    01427     }
    01428
    01429     if (t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
    01430       /* Part of orders */
    01431       v->DeleteUnreachedImplicitOrders();
    01432       UpdateVehicleTimetable(v, true);
    01433       v->IncrementImplicitOrderIndex();
    01434     }
    01435     if (t.GetDepotActionType() & ODATFB_HALT) {
    01436       /* Vehicles are always stopped on entering depots. Do not restart this one. */
    01437       _vehicles_to_autoreplace[v] = false;
    01438       if (v->owner == _local_company) {
    01439         SetDParam(0, v->index);
    01440         AddVehicleAdviceNewsItem(STR_NEWS_TRAIN_IS_WAITING + v->type, v->index);
    01441       }
    01442       AI::NewEvent(v->owner, new ScriptEventVehicleWaitingInDepot(v->index));
    01443     }
    01444   }
    01445 }
    01446
    01447
    01453 void VehicleUpdatePosition(Vehicle *v)
    01454 {
    01455   UpdateVehicleTileHash(v, false);
    01456 }
    01457
    01464 void VehicleUpdateViewport(Vehicle *v, bool dirty)
    01465 {
    01466   int img = v->cur_image;
    01467   Point pt = RemapCoords(v->x_pos + v->x_offs, v->y_pos + v->y_offs, v->z_pos);
    01468   const Sprite *spr = GetSprite(img, ST_NORMAL);
    01469
    01470   pt.x += spr->x_offs;
    01471   pt.y += spr->y_offs;
    01472
    01473   UpdateVehicleViewportHash(v, pt.x, pt.y);
    01474
    01475   Rect old_coord = v->coord;
    01476   v->coord.left   = pt.x;
    01477   v->coord.top    = pt.y;
    01478   v->coord.right  = pt.x + spr->width + 2 * ZOOM_LVL_BASE;
    01479   v->coord.bottom = pt.y + spr->height + 2 * ZOOM_LVL_BASE;
    01480
    01481   if (dirty) {
    01482     if (old_coord.left == INVALID_COORD) {
    01483       MarkSingleVehicleDirty(v);
    01484     } else {
    01485       MarkAllViewportsDirty(
    01486         min(old_coord.left,   v->coord.left),
    01487         min(old_coord.top,    v->coord.top),
    01488         max(old_coord.right,  v->coord.right) + 1 * ZOOM_LVL_BASE,
    01489         max(old_coord.bottom, v->coord.bottom) + 1 * ZOOM_LVL_BASE
    01490       );
    01491     }
    01492   }
    01493 }
    01494
    01499 void VehicleUpdatePositionAndViewport(Vehicle *v)
    01500 {
    01501   VehicleUpdatePosition(v);
    01502   VehicleUpdateViewport(v, true);
    01503 }
    01504
    01509 void MarkSingleVehicleDirty(const Vehicle *v)
    01510 {
    01511   MarkAllViewportsDirty(v->coord.left, v->coord.top, v->coord.right + 1 * ZOOM_LVL_BASE, v->coord.bottom + 1 * ZOOM_LVL_BASE);
    01512 }
    01513
    01519 GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
    01520 {
    01521   static const int8 _delta_coord[16] = {
    01522     -1,-1,-1, 0, 1, 1, 1, 0, /* x */
    01523     -1, 0, 1, 1, 1, 0,-1,-1, /* y */
    01524   };
    01525
    01526   int x = v->x_pos + _delta_coord[v->direction];
    01527   int y = v->y_pos + _delta_coord[v->direction + 8];
    01528
    01529   GetNewVehiclePosResult gp;
    01530   gp.x = x;
    01531   gp.y = y;
    01532   gp.old_tile = v->tile;
    01533   gp.new_tile = TileVirtXY(x, y);
    01534   return gp;
    01535 }
    01536
    01537 static const Direction _new_direction_table[] = {
    01538   DIR_N,  DIR_NW, DIR_W,
    01539   DIR_NE, DIR_SE, DIR_SW,
    01540   DIR_E,  DIR_SE, DIR_S
    01541 };
    01542
    01543 Direction GetDirectionTowards(const Vehicle *v, int x, int y)
    01544 {
    01545   int i = 0;
    01546
    01547   if (y >= v->y_pos) {
    01548     if (y != v->y_pos) i += 3;
    01549     i += 3;
    01550   }
    01551
    01552   if (x >= v->x_pos) {
    01553     if (x != v->x_pos) i++;
    01554     i++;
    01555   }
    01556
    01557   Direction dir = v->direction;
    01558
    01559   DirDiff dirdiff = DirDifference(_new_direction_table[i], dir);
    01560   if (dirdiff == DIRDIFF_SAME) return dir;
    01561   return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
    01562 }
    01563
    01573 VehicleEnterTileStatus VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
    01574 {
    01575   return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
    01576 }
    01577
    01585 FreeUnitIDGenerator::FreeUnitIDGenerator(VehicleType type, CompanyID owner) : cache(NULL), maxid(0), curid(0)
    01586 {
    01587   /* Find maximum */
    01588   const Vehicle *v;
    01589   FOR_ALL_VEHICLES(v) {
    01590     if (v->type == type && v->owner == owner) {
    01591       this->maxid = max<UnitID>(this->maxid, v->unitnumber);
    01592     }
    01593   }
    01594
    01595   if (this->maxid == 0) return;
    01596
    01597   /* Reserving 'maxid + 2' because we need:
    01598    * - space for the last item (with v->unitnumber == maxid)
    01599    * - one free slot working as loop terminator in FreeUnitIDGenerator::NextID() */
    01600   this->cache = CallocT<bool>(this->maxid + 2);
    01601
    01602   /* Fill the cache */
    01603   FOR_ALL_VEHICLES(v) {
    01604     if (v->type == type && v->owner == owner) {
    01605       this->cache[v->unitnumber] = true;
    01606     }
    01607   }
    01608 }
    01609
    01611 UnitID FreeUnitIDGenerator::NextID()
    01612 {
    01613   if (this->maxid <= this->curid) return ++this->curid;
    01614
    01615   while (this->cache[++this->curid]) { } // it will stop, we reserved more space than needed
    01616
    01617   return this->curid;
    01618 }
    01619
    01625 UnitID GetFreeUnitNumber(VehicleType type)
    01626 {
    01627   /* Check whether it is allowed to build another vehicle. */
    01628   uint max_veh;
    01629   switch (type) {
    01630     case VEH_TRAIN:    max_veh = _settings_game.vehicle.max_trains;   break;
    01631     case VEH_ROAD:     max_veh = _settings_game.vehicle.max_roadveh;  break;
    01632     case VEH_SHIP:     max_veh = _settings_game.vehicle.max_ships;    break;
    01633     case VEH_AIRCRAFT: max_veh = _settings_game.vehicle.max_aircraft; break;
    01634     default: NOT_REACHED();
    01635   }
    01636
    01637   const Company *c = Company::Get(_current_company);
    01638   if (c->group_all[type].num_vehicle >= max_veh) return UINT16_MAX; // Currently already at the limit, no room to make a new one.
    01639
    01640   FreeUnitIDGenerator gen(type, _current_company);
    01641
    01642   return gen.NextID();
    01643 }
    01644
    01645
    01654 bool CanBuildVehicleInfrastructure(VehicleType type)
    01655 {
    01656   assert(IsCompanyBuildableVehicleType(type));
    01657
    01658   if (!Company::IsValidID(_local_company)) return false;
    01659   if (!_settings_client.gui.disable_unsuitable_building) return true;
    01660
    01661   UnitID max;
    01662   switch (type) {
    01663     case VEH_TRAIN:    max = _settings_game.vehicle.max_trains; break;
    01664     case VEH_ROAD:     max = _settings_game.vehicle.max_roadveh; break;
    01665     case VEH_SHIP:     max = _settings_game.vehicle.max_ships; break;
    01666     case VEH_AIRCRAFT: max = _settings_game.vehicle.max_aircraft; break;
    01667     default: NOT_REACHED();
    01668   }
    01669
    01670   /* We can build vehicle infrastructure when we may build the vehicle type */
    01671   if (max > 0) {
    01672     /* Can we actually build the vehicle type? */
    01673     const Engine *e;
    01674     FOR_ALL_ENGINES_OF_TYPE(e, type) {
    01675       if (HasBit(e->company_avail, _local_company)) return true;
    01676     }
    01677     return false;
    01678   }
    01679
    01680   /* We should be able to build infrastructure when we have the actual vehicle type */
    01681   const Vehicle *v;
    01682   FOR_ALL_VEHICLES(v) {
    01683     if (v->owner == _local_company && v->type == type) return true;
    01684   }
    01685
    01686   return false;
    01687 }
    01688
    01689
    01697 LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
    01698 {
    01699   CargoID cargo_type = v == NULL ? (CargoID)CT_INVALID : v->cargo_type;
    01700   const Engine *e = Engine::Get(engine_type);
    01701   switch (e->type) {
    01702     default: NOT_REACHED();
    01703     case VEH_TRAIN:
    01704       if (v != NULL && parent_engine_type != INVALID_ENGINE && (UsesWagonOverride(v) || (v->IsArticulatedPart() && e->u.rail.railveh_type != RAILVEH_WAGON))) {
    01705         /* Wagonoverrides use the colour scheme of the front engine.
    01706          * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */
    01707         engine_type = parent_engine_type;
    01708         e = Engine::Get(engine_type);
    01709         /* Note: Luckily cargo_type is not needed for engines */
    01710       }
    01711
    01712       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01713       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01714       if (e->u.rail.railveh_type == RAILVEH_WAGON) {
    01715         if (!CargoSpec::Get(cargo_type)->is_freight) {
    01716           if (parent_engine_type == INVALID_ENGINE) {
    01717             return LS_PASSENGER_WAGON_STEAM;
    01718           } else {
    01719             switch (RailVehInfo(parent_engine_type)->engclass) {
    01720               default: NOT_REACHED();
    01721               case EC_STEAM:    return LS_PASSENGER_WAGON_STEAM;
    01722               case EC_DIESEL:   return LS_PASSENGER_WAGON_DIESEL;
    01723               case EC_ELECTRIC: return LS_PASSENGER_WAGON_ELECTRIC;
    01724               case EC_MONORAIL: return LS_PASSENGER_WAGON_MONORAIL;
    01725               case EC_MAGLEV:   return LS_PASSENGER_WAGON_MAGLEV;
    01726             }
    01727           }
    01728         } else {
    01729           return LS_FREIGHT_WAGON;
    01730         }
    01731       } else {
    01732         bool is_mu = HasBit(e->info.misc_flags, EF_RAIL_IS_MU);
    01733
    01734         switch (e->u.rail.engclass) {
    01735           default: NOT_REACHED();
    01736           case EC_STEAM:    return LS_STEAM;
    01737           case EC_DIESEL:   return is_mu ? LS_DMU : LS_DIESEL;
    01738           case EC_ELECTRIC: return is_mu ? LS_EMU : LS_ELECTRIC;
    01739           case EC_MONORAIL: return LS_MONORAIL;
    01740           case EC_MAGLEV:   return LS_MAGLEV;
    01741         }
    01742       }
    01743
    01744     case VEH_ROAD:
    01745       /* Always use the livery of the front */
    01746       if (v != NULL && parent_engine_type != INVALID_ENGINE) {
    01747         engine_type = parent_engine_type;
    01748         e = Engine::Get(engine_type);
    01749         cargo_type = v->First()->cargo_type;
    01750       }
    01751       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01752       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01753
    01754       /* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */
    01755       if (HasBit(e->info.misc_flags, EF_ROAD_TRAM)) {
    01756         /* Tram */
    01757         return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
    01758       } else {
    01759         /* Bus or truck */
    01760         return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_BUS : LS_TRUCK;
    01761       }
    01762
    01763     case VEH_SHIP:
    01764       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01765       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01766       return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
    01767
    01768     case VEH_AIRCRAFT:
    01769       switch (e->u.air.subtype) {
    01770         case AIR_HELI: return LS_HELICOPTER;
    01771         case AIR_CTOL: return LS_SMALL_PLANE;
    01772         case AIR_CTOL | AIR_FAST: return LS_LARGE_PLANE;
    01773         default: NOT_REACHED();
    01774       }
    01775   }
    01776 }
    01777
    01787 const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, byte livery_setting)
    01788 {
    01789   const Company *c = Company::Get(company);
    01790   LiveryScheme scheme = LS_DEFAULT;
    01791
    01792   /* The default livery is always available for use, but its in_use flag determines
    01793    * whether any _other_ liveries are in use. */
    01794   if (c->livery[LS_DEFAULT].in_use && (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company))) {
    01795     /* Determine the livery scheme to use */
    01796     scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
    01797
    01798     /* Switch back to the default scheme if the resolved scheme is not in use */
    01799     if (!c->livery[scheme].in_use) scheme = LS_DEFAULT;
    01800   }
    01801
    01802   return &c->livery[scheme];
    01803 }
    01804
    01805
    01806 static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
    01807 {
    01808   PaletteID map = (v != NULL) ? v->colourmap : PAL_NONE;
    01809
    01810   /* Return cached value if any */
    01811   if (map != PAL_NONE) return map;
    01812
    01813   const Engine *e = Engine::Get(engine_type);
    01814
    01815   /* Check if we should use the colour map callback */
    01816   if (HasBit(e->info.callback_mask, CBM_VEHICLE_COLOUR_REMAP)) {
    01817     uint16 callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
    01818     /* Failure means "use the default two-colour" */
    01819     if (callback != CALLBACK_FAILED) {
    01820       assert_compile(PAL_NONE == 0); // Returning 0x4000 (resp. 0xC000) coincidences with default value (PAL_NONE)
    01821       map = GB(callback, 0, 14);
    01822       /* If bit 14 is set, then the company colours are applied to the
    01823        * map else it's returned as-is. */
    01824       if (!HasBit(callback, 14)) {
    01825         /* Update cache */
    01826         if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
    01827         return map;
    01828       }
    01829     }
    01830   }
    01831
    01832   bool twocc = HasBit(e->info.misc_flags, EF_USES_2CC);
    01833
    01834   if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
    01835
    01836   /* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
    01837   if (!Company::IsValidID(company)) return map;
    01838
    01839   const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries);
    01840
    01841   map += livery->colour1;
    01842   if (twocc) map += livery->colour2 * 16;
    01843
    01844   /* Update cache */
    01845   if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
    01846   return map;
    01847 }
    01848
    01855 PaletteID GetEnginePalette(EngineID engine_type, CompanyID company)
    01856 {
    01857   return GetEngineColourMap(engine_type, company, INVALID_ENGINE, NULL);
    01858 }
    01859
    01865 PaletteID GetVehiclePalette(const Vehicle *v)
    01866 {
    01867   if (v->IsGroundVehicle()) {
    01868     return GetEngineColourMap(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v);
    01869   }
    01870
    01871   return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
    01872 }
    01873
    01877 void Vehicle::DeleteUnreachedImplicitOrders()
    01878 {
    01879   if (this->IsGroundVehicle()) {
    01880     uint16 &gv_flags = this->GetGroundVehicleFlags();
    01881     if (HasBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS)) {
    01882       /* Do not delete orders, only skip them */
    01883       ClrBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
    01884       this->cur_implicit_order_index = this->cur_real_order_index;
    01885       InvalidateVehicleOrder(this, 0);
    01886       return;
    01887     }
    01888   }
    01889
    01890   const Order *order = this->GetOrder(this->cur_implicit_order_index);
    01891   while (order != NULL) {
    01892     if (this->cur_implicit_order_index == this->cur_real_order_index) break;
    01893
    01894     if (order->IsType(OT_IMPLICIT)) {
    01895       DeleteOrder(this, this->cur_implicit_order_index);
    01896       /* DeleteOrder does various magic with order_indices, so resync 'order' with 'cur_implicit_order_index' */
    01897       order = this->GetOrder(this->cur_implicit_order_index);
    01898     } else {
    01899       /* Skip non-implicit orders, e.g. service-orders */
    01900       order = order->next;
    01901       this->cur_implicit_order_index++;
    01902     }
    01903
    01904     /* Wrap around */
    01905     if (order == NULL) {
    01906       order = this->GetOrder(0);
    01907       this->cur_implicit_order_index = 0;
    01908     }
    01909   }
    01910 }
    01911
    01916 void Vehicle::BeginLoading()
    01917 {
    01918   assert(IsTileType(this->tile, MP_STATION) || this->type == VEH_SHIP);
    01919
    01920   if (this->current_order.IsType(OT_GOTO_STATION) &&
    01921       this->current_order.GetDestination() == this->last_station_visited) {
    01922     this->DeleteUnreachedImplicitOrders();
    01923
    01924     /* Now both order indices point to the destination station, and we can start loading */
    01925     this->current_order.MakeLoading(true);
    01926     UpdateVehicleTimetable(this, true);
    01927
    01928     /* Furthermore add the Non Stop flag to mark that this station
    01929      * is the actual destination of the vehicle, which is (for example)
    01930      * necessary to be known for HandleTrainLoading to determine
    01931      * whether the train is lost or not; not marking a train lost
    01932      * that arrives at random stations is bad. */
    01933     this->current_order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
    01934
    01935   } else {
    01936     /* We weren't scheduled to stop here. Insert an implicit order
    01937      * to show that we are stopping here, but only do that if the order
    01938      * list isn't empty.
    01939      * While only groundvehicles have implicit orders, e.g. aircraft might still enter
    01940      * the 'wrong' terminal when skipping orders etc. */
    01941     Order *in_list = this->GetOrder(this->cur_implicit_order_index);
    01942     if (this->IsGroundVehicle() && in_list != NULL &&
    01943         (!in_list->IsType(OT_IMPLICIT) ||
    01944         in_list->GetDestination() != this->last_station_visited)) {
    01945       bool suppress_implicit_orders = HasBit(this->GetGroundVehicleFlags(), GVF_SUPPRESS_IMPLICIT_ORDERS);
    01946       /* Do not create consecutive duplicates of implicit orders */
    01947       Order *prev_order = this->cur_implicit_order_index > 0 ? this->GetOrder(this->cur_implicit_order_index - 1) : (this->GetNumOrders() > 1 ? this->GetLastOrder() : NULL);
    01948       if (prev_order == NULL ||
    01949           (!prev_order->IsType(OT_IMPLICIT) && !prev_order->IsType(OT_GOTO_STATION)) ||
    01950           prev_order->GetDestination() != this->last_station_visited) {
    01951
    01952         /* Prefer deleting implicit orders instead of inserting new ones,
    01953          * so test whether the right order follows later */
    01954         int target_index = this->cur_implicit_order_index;
    01955         bool found = false;
    01956         while (target_index != this->cur_real_order_index) {
    01957           const Order *order = this->GetOrder(target_index);
    01958           if (order->IsType(OT_IMPLICIT) && order->GetDestination() == this->last_station_visited) {
    01959             found = true;
    01960             break;
    01961           }
    01962           target_index++;
    01963           if (target_index >= this->orders.list->GetNumOrders()) target_index = 0;
    01964           assert(target_index != this->cur_implicit_order_index); // infinite loop?
    01965         }
    01966
    01967         if (found) {
    01968           if (suppress_implicit_orders) {
    01969             /* Skip to the found order */
    01970             this->cur_implicit_order_index = target_index;
    01971             InvalidateVehicleOrder(this, 0);
    01972           } else {
    01973             /* Delete all implicit orders up to the station we just reached */
    01974             const Order *order = this->GetOrder(this->cur_implicit_order_index);
    01975             while (!order->IsType(OT_IMPLICIT) || order->GetDestination() != this->last_station_visited) {
    01976               if (order->IsType(OT_IMPLICIT)) {
    01977                 DeleteOrder(this, this->cur_implicit_order_index);
    01978                 /* DeleteOrder does various magic with order_indices, so resync 'order' with 'cur_implicit_order_index' */
    01979                 order = this->GetOrder(this->cur_implicit_order_index);
    01980               } else {
    01981                 /* Skip non-implicit orders, e.g. service-orders */
    01982                 order = order->next;
    01983                 this->cur_implicit_order_index++;
    01984               }
    01985
    01986               /* Wrap around */
    01987               if (order == NULL) {
    01988                 order = this->GetOrder(0);
    01989                 this->cur_implicit_order_index = 0;
    01990               }
    01991               assert(order != NULL);
    01992             }
    01993           }
    01994         } else if (!suppress_implicit_orders && this->orders.list->GetNumOrders() < MAX_VEH_ORDER_ID && Order::CanAllocateItem()) {
    01995           /* Insert new implicit order */
    01996           Order *implicit_order = new Order();
    01997           implicit_order->MakeImplicit(this->last_station_visited);
    01998           InsertOrder(this, implicit_order, this->cur_implicit_order_index);
    01999           if (this->cur_implicit_order_index > 0) --this->cur_implicit_order_index;
    02000
    02001           /* InsertOrder disabled creation of implicit orders for all vehicles with the same implicit order.
    02002            * Reenable it for this vehicle */
    02003           uint16 &gv_flags = this->GetGroundVehicleFlags();
    02004           ClrBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
    02005         }
    02006       }
    02007     }
    02008     this->current_order.MakeLoading(false);
    02009   }
    02010
    02011   Station::Get(this->last_station_visited)->loading_vehicles.push_back(this);
    02012
    02013   PrepareUnload(this);
    02014
    02015   SetWindowDirty(GetWindowClassForVehicleType(this->type), this->owner);
    02016   SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
    02017   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
    02018   SetWindowDirty(WC_STATION_VIEW, this->last_station_visited);
    02019
    02020   Station::Get(this->last_station_visited)->MarkTilesDirty(true);
    02021   this->cur_speed = 0;
    02022   this->MarkDirty();
    02023 }
    02024
    02029 void Vehicle::LeaveStation()
    02030 {
    02031   assert(this->current_order.IsType(OT_LOADING));
    02032
    02033   delete this->cargo_payment;
    02034
    02035   /* Only update the timetable if the vehicle was supposed to stop here. */
    02036   if (this->current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE) UpdateVehicleTimetable(this, false);
    02037
    02038   this->current_order.MakeLeaveStation();
    02039   Station *st = Station::Get(this->last_station_visited);
    02040   st->loading_vehicles.remove(this);
    02041
    02042   HideFillingPercent(&this->fill_percent_te_id);
    02043
    02044   if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) {
    02045     /* Trigger station animation (trains only) */
    02046     if (IsTileType(this->tile, MP_STATION)) {
    02047       TriggerStationRandomisation(st, this->tile, SRT_TRAIN_DEPARTS);
    02048       TriggerStationAnimation(st, this->tile, SAT_TRAIN_DEPARTS);
    02049     }
    02050
    02051     SetBit(Train::From(this)->flags, VRF_LEAVING_STATION);
    02052   }
    02053 }
    02054
    02055
    02061 void Vehicle::HandleLoading(bool mode)
    02062 {
    02063   switch (this->current_order.GetType()) {
    02064     case OT_LOADING: {
    02065       uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0);
    02066
    02067       /* Not the first call for this tick, or still loading */
    02068       if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || this->current_order_time < wait_time) return;
    02069
    02070       this->PlayLeaveStationSound();
    02071
    02072       this->LeaveStation();
    02073
    02074       /* Only advance to next order if we just loaded at the current one */
    02075       const Order *order = this->GetOrder(this->cur_implicit_order_index);
    02076       if (order == NULL ||
    02077           (!order->IsType(OT_IMPLICIT) && !order->IsType(OT_GOTO_STATION)) ||
    02078           order->GetDestination() != this->last_station_visited) {
    02079         return;
    02080       }
    02081       break;
    02082     }
    02083
    02084     case OT_DUMMY: break;
    02085
    02086     default: return;
    02087   }
    02088
    02089   this->IncrementImplicitOrderIndex();
    02090 }
    02091
    02098 CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command)
    02099 {
    02100   CommandCost ret = CheckOwnership(this->owner);
    02101   if (ret.Failed()) return ret;
    02102
    02103   if (this->vehstatus & VS_CRASHED) return CMD_ERROR;
    02104   if (this->IsStoppedInDepot()) return CMD_ERROR;
    02105
    02106   if (this->current_order.IsType(OT_GOTO_DEPOT)) {
    02107     bool halt_in_depot = (this->current_order.GetDepotActionType() & ODATFB_HALT) != 0;
    02108     if (!!(command & DEPOT_SERVICE) == halt_in_depot) {
    02109       /* We called with a different DEPOT_SERVICE setting.
    02110        * Now we change the setting to apply the new one and let the vehicle head for the same depot.
    02111        * Note: the if is (true for requesting service == true for ordered to stop in depot)          */
    02112       if (flags & DC_EXEC) {
    02113         this->current_order.SetDepotOrderType(ODTF_MANUAL);
    02114         this->current_order.SetDepotActionType(halt_in_depot ? ODATF_SERVICE_ONLY : ODATFB_HALT);
    02115         SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
    02116       }
    02117       return CommandCost();
    02118     }
    02119
    02120     if (command & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
    02121     if (flags & DC_EXEC) {
    02122       /* If the orders to 'goto depot' are in the orders list (forced servicing),
    02123        * then skip to the next order; effectively cancelling this forced service */
    02124       if (this->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) this->IncrementRealOrderIndex();
    02125
    02126       if (this->IsGroundVehicle()) {
    02127         uint16 &gv_flags = this->GetGroundVehicleFlags();
    02128         SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
    02129       }
    02130
    02131       this->current_order.MakeDummy();
    02132       SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
    02133     }
    02134     return CommandCost();
    02135   }
    02136
    02137   TileIndex location;
    02138   DestinationID destination;
    02139   bool reverse;
    02140   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};
    02141   if (!this->FindClosestDepot(&location, &destination, &reverse)) return_cmd_error(no_depot[this->type]);
    02142
    02143   if (flags & DC_EXEC) {
    02144     if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
    02145
    02146     if (this->IsGroundVehicle()) {
    02147       uint16 &gv_flags = this->GetGroundVehicleFlags();
    02148       SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
    02149     }
    02150
    02151     this->dest_tile = location;
    02152     this->current_order.MakeGoToDepot(destination, ODTF_MANUAL);
    02153     if (!(command & DEPOT_SERVICE)) this->current_order.SetDepotActionType(ODATFB_HALT);
    02154     SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
    02155
    02156     /* If there is no depot in front, reverse automatically (trains only) */
    02157     if (this->type == VEH_TRAIN && reverse) DoCommand(this->tile, this->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
    02158
    02159     if (this->type == VEH_AIRCRAFT) {
    02160       Aircraft *a = Aircraft::From(this);
    02161       if (a->state == FLYING && a->targetairport != destination) {
    02162         /* The aircraft is now heading for a different hangar than the next in the orders */
    02163         extern void AircraftNextAirportPos_and_Order(Aircraft *a);
    02164         AircraftNextAirportPos_and_Order(a);
    02165       }
    02166     }
    02167   }
    02168
    02169   return CommandCost();
    02170
    02171 }
    02172
    02177 void Vehicle::UpdateVisualEffect(bool allow_power_change)
    02178 {
    02179   bool powered_before = HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
    02180   const Engine *e = this->GetEngine();
    02181
    02182   /* Evaluate properties */
    02183   byte visual_effect;
    02184   switch (e->type) {
    02185     case VEH_TRAIN: visual_effect = e->u.rail.visual_effect; break;
    02186     case VEH_ROAD:  visual_effect = e->u.road.visual_effect; break;
    02187     case VEH_SHIP:  visual_effect = e->u.ship.visual_effect; break;
    02188     default:        visual_effect = 1 << VE_DISABLE_EFFECT;  break;
    02189   }
    02190
    02191   /* Check powered wagon / visual effect callback */
    02192   if (HasBit(e->info.callback_mask, CBM_VEHICLE_VISUAL_EFFECT)) {
    02193     uint16 callback = GetVehicleCallback(CBID_VEHICLE_VISUAL_EFFECT, 0, 0, this->engine_type, this);
    02194
    02195     if (callback != CALLBACK_FAILED) {
    02196       if (callback >= 0x100 && e->GetGRF()->grf_version >= 8) ErrorUnknownCallbackResult(e->GetGRFID(), CBID_VEHICLE_VISUAL_EFFECT, callback);
    02197
    02198       callback = GB(callback, 0, 8);
    02199       /* Avoid accidentally setting 'visual_effect' to the default value
    02200        * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
    02201       if (callback == VE_DEFAULT) {
    02202         assert(HasBit(callback, VE_DISABLE_EFFECT));
    02203         SB(callback, VE_TYPE_START, VE_TYPE_COUNT, 0);
    02204       }
    02205       visual_effect = callback;
    02206     }
    02207   }
    02208
    02209   /* Apply default values */
    02210   if (visual_effect == VE_DEFAULT ||
    02211       (!HasBit(visual_effect, VE_DISABLE_EFFECT) && GB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT) == VE_TYPE_DEFAULT)) {
    02212     /* Only train engines have default effects.
    02213      * Note: This is independent of whether the engine is a front engine or articulated part or whatever. */
    02214     if (e->type != VEH_TRAIN || e->u.rail.railveh_type == RAILVEH_WAGON || !IsInsideMM(e->u.rail.engclass, EC_STEAM, EC_MONORAIL)) {
    02215       if (visual_effect == VE_DEFAULT) {
    02216         visual_effect = 1 << VE_DISABLE_EFFECT;
    02217       } else {
    02218         SetBit(visual_effect, VE_DISABLE_EFFECT);
    02219       }
    02220     } else {
    02221       if (visual_effect == VE_DEFAULT) {
    02222         /* Also set the offset */
    02223         visual_effect = (VE_OFFSET_CENTRE - (e->u.rail.engclass == EC_STEAM ? 4 : 0)) << VE_OFFSET_START;
    02224       }
    02225       SB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT, e->u.rail.engclass - EC_STEAM + VE_TYPE_STEAM);
    02226     }
    02227   }
    02228
    02229   this->vcache.cached_vis_effect = visual_effect;
    02230
    02231   if (!allow_power_change && powered_before != HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
    02232     ToggleBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
    02233     ShowNewGrfVehicleError(this->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_POWERED_WAGON, GBUG_VEH_POWERED_WAGON, false);
    02234   }
    02235 }
    02236
    02237 static const int8 _vehicle_smoke_pos[8] = {
    02238   1, 1, 1, 0, -1, -1, -1, 0
    02239 };
    02240
    02245 void Vehicle::ShowVisualEffect() const
    02246 {
    02247   assert(this->IsPrimaryVehicle());
    02248   bool sound = false;
    02249
    02250   /* Do not show any smoke when:
    02251    * - vehicle smoke is disabled by the player
    02252    * - the vehicle is slowing down or stopped (by the player)
    02253    * - the vehicle is moving very slowly
    02254    */
    02255   if (_settings_game.vehicle.smoke_amount == 0 ||
    02256       this->vehstatus & (VS_TRAIN_SLOWING | VS_STOPPED) ||
    02257       this->cur_speed < 2) {
    02258     return;
    02259   }
    02260
    02261   uint max_speed = this->vcache.cached_max_speed;
    02262   if (this->type == VEH_TRAIN) {
    02263     const Train *t = Train::From(this);
    02264     /* For trains, do not show any smoke when:
    02265      * - the train is reversing
    02266      * - is entering a station with an order to stop there and its speed is equal to maximum station entering speed
    02267      */
    02268     if (HasBit(t->flags, VRF_REVERSING) ||
    02269         (IsRailStationTile(t->tile) && t->IsFrontEngine() && t->current_order.ShouldStopAtStation(t, GetStationIndex(t->tile)) &&
    02270         t->cur_speed >= t->Train::GetCurrentMaxSpeed())) {
    02271       return;
    02272     }
    02273
    02274     max_speed = min(max_speed, t->gcache.cached_max_track_speed);
    02275     max_speed = min(max_speed, this->current_order.max_speed);
    02276   }
    02277   if (this->type == VEH_ROAD || this->type == VEH_SHIP) max_speed = min(max_speed, this->current_order.max_speed * 2);
    02278
    02279   const Vehicle *v = this;
    02280
    02281   do {
    02282     int effect_offset = GB(v->vcache.cached_vis_effect, VE_OFFSET_START, VE_OFFSET_COUNT) - VE_OFFSET_CENTRE;
    02283     byte effect_type = GB(v->vcache.cached_vis_effect, VE_TYPE_START, VE_TYPE_COUNT);
    02284     bool disable_effect = HasBit(v->vcache.cached_vis_effect, VE_DISABLE_EFFECT);
    02285
    02286     /* Show no smoke when:
    02287      * - Smoke has been disabled for this vehicle
    02288      * - The vehicle is not visible
    02289      * - The vehicle is under a bridge
    02290      * - The vehicle is on a depot tile
    02291      * - The vehicle is on a tunnel tile
    02292      * - The vehicle is a train engine that is currently unpowered */
    02293     if (disable_effect ||
    02294         v->vehstatus & VS_HIDDEN ||
    02295         (MayHaveBridgeAbove(v->tile) && IsBridgeAbove(v->tile)) ||
    02296         IsDepotTile(v->tile) ||
    02297         IsTunnelTile(v->tile) ||
    02298         (v->type == VEH_TRAIN &&
    02299         !HasPowerOnRail(Train::From(v)->railtype, GetTileRailType(v->tile)))) {
    02300       continue;
    02301     }
    02302
    02303     /* The effect offset is relative to a point 4 units behind the vehicle's
    02304      * front (which is the center of an 8/8 vehicle). Shorter vehicles need a
    02305      * correction factor. */
    02306     if (v->type == VEH_TRAIN) effect_offset += (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
    02307
    02308     int x = _vehicle_smoke_pos[v->direction] * effect_offset;
    02309     int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
    02310
    02311     if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) {
    02312       x = -x;
    02313       y = -y;
    02314     }
    02315
    02316     switch (effect_type) {
    02317       case VE_TYPE_STEAM:
    02318         /* Steam smoke - amount is gradually falling until vehicle reaches its maximum speed, after that it's normal.
    02319          * Details: while vehicle's current speed is gradually increasing, steam plumes' density decreases by one third each
    02320          * third of its maximum speed spectrum. Steam emission finally normalises at very close to vehicle's maximum speed.
    02321          * REGULATION:
    02322          * - instead of 1, 4 / 2^smoke_amount (max. 2) is used to provide sufficient regulation to steam puffs' amount. */
    02323         if (GB(v->tick_counter, 0, ((4 >> _settings_game.vehicle.smoke_amount) + ((this->cur_speed * 3) / max_speed))) == 0) {
    02324           CreateEffectVehicleRel(v, x, y, 10, EV_STEAM_SMOKE);
    02325           sound = true;
    02326         }
    02327         break;
    02328
    02329       case VE_TYPE_DIESEL: {
    02330         /* Diesel smoke - thicker when vehicle is starting, gradually subsiding till it reaches its maximum speed
    02331          * when smoke emission stops.
    02332          * Details: Vehicle's (max.) speed spectrum is divided into 32 parts. When max. speed is reached, chance for smoke
    02333          * emission erodes by 32 (1/4). For trains, power and weight come in handy too to either increase smoke emission in
    02334          * 6 steps (1000HP each) if the power is low or decrease smoke emission in 6 steps (512 tonnes each) if the train
    02335          * isn't overweight. Power and weight contributions are expressed in a way that neither extreme power, nor
    02336          * extreme weight can ruin the balance (e.g. FreightWagonMultiplier) in the formula. When the vehicle reaches
    02337          * maximum speed no diesel_smoke is emitted.
    02338          * REGULATION:
    02339          * - up to which speed a diesel vehicle is emitting smoke (with reduced/small setting only until 1/2 of max_speed),
    02340          * - in Chance16 - the last value is 512 / 2^smoke_amount (max. smoke when 128 = smoke_amount of 2). */
    02341         int power_weight_effect = 0;
    02342         if (v->type == VEH_TRAIN) {
    02343           power_weight_effect = (32 >> (Train::From(this)->gcache.cached_power >> 10)) - (32 >> (Train::From(this)->gcache.cached_weight >> 9));
    02344         }
    02345         if (this->cur_speed < (max_speed >> (2 >> _settings_game.vehicle.smoke_amount)) &&
    02346             Chance16((64 - ((this->cur_speed << 5) / max_speed) + power_weight_effect), (512 >> _settings_game.vehicle.smoke_amount))) {
    02347           CreateEffectVehicleRel(v, x, y, 10, EV_DIESEL_SMOKE);
    02348           sound = true;
    02349         }
    02350         break;
    02351       }
    02352
    02353       case VE_TYPE_ELECTRIC:
    02354         /* Electric train's spark - more often occurs when train is departing (more load)
    02355          * Details: Electric locomotives are usually at least twice as powerful as their diesel counterparts, so spark
    02356          * emissions are kept simple. Only when starting, creating huge force are sparks more likely to happen, but when
    02357          * reaching its max. speed, quarter by quarter of it, chance decreases until the usual 2,22% at train's top speed.
    02358          * REGULATION:
    02359          * - in Chance16 the last value is 360 / 2^smoke_amount (max. sparks when 90 = smoke_amount of 2). */
    02360         if (GB(v->tick_counter, 0, 2) == 0 &&
    02361             Chance16((6 - ((this->cur_speed << 2) / max_speed)), (360 >> _settings_game.vehicle.smoke_amount))) {
    02362           CreateEffectVehicleRel(v, x, y, 10, EV_ELECTRIC_SPARK);
    02363           sound = true;
    02364         }
    02365         break;
    02366
    02367       default:
    02368         break;
    02369     }
    02370   } while ((v = v->Next()) != NULL);
    02371
    02372   if (sound) PlayVehicleSound(this, VSE_VISUAL_EFFECT);
    02373 }
    02374
    02379 void Vehicle::SetNext(Vehicle *next)
    02380 {
    02381   assert(this != next);
    02382
    02383   if (this->next != NULL) {
    02384     /* We had an old next vehicle. Update the first and previous pointers */
    02385     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
    02386       v->first = this->next;
    02387     }
    02388     this->next->previous = NULL;
    02389   }
    02390
    02391   this->next = next;
    02392
    02393   if (this->next != NULL) {
    02394     /* A new next vehicle. Update the first and previous pointers */
    02395     if (this->next->previous != NULL) this->next->previous->next = NULL;
    02396     this->next->previous = this;
    02397     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
    02398       v->first = this->first;
    02399     }
    02400   }
    02401 }
    02402
    02408 void Vehicle::AddToShared(Vehicle *shared_chain)
    02409 {
    02410   assert(this->previous_shared == NULL && this->next_shared == NULL);
    02411
    02412   if (shared_chain->orders.list == NULL) {
    02413     assert(shared_chain->previous_shared == NULL);
    02414     assert(shared_chain->next_shared == NULL);
    02415     this->orders.list = shared_chain->orders.list = new OrderList(NULL, shared_chain);
    02416   }
    02417
    02418   this->next_shared     = shared_chain->next_shared;
    02419   this->previous_shared = shared_chain;
    02420
    02421   shared_chain->next_shared = this;
    02422
    02423   if (this->next_shared != NULL) this->next_shared->previous_shared = this;
    02424
    02425   shared_chain->orders.list->AddVehicle(this);
    02426 }
    02427
    02431 void Vehicle::RemoveFromShared()
    02432 {
    02433   /* Remember if we were first and the old window number before RemoveVehicle()
    02434    * as this changes first if needed. */
    02435   bool were_first = (this->FirstShared() == this);
    02436   VehicleListIdentifier vli(VL_SHARED_ORDERS, this->type, this->owner, this->FirstShared()->index);
    02437
    02438   this->orders.list->RemoveVehicle(this);
    02439
    02440   if (!were_first) {
    02441     /* We are not the first shared one, so only relink our previous one. */
    02442     this->previous_shared->next_shared = this->NextShared();
    02443   }
    02444
    02445   if (this->next_shared != NULL) this->next_shared->previous_shared = this->previous_shared;
    02446
    02447
    02448   if (this->orders.list->GetNumVehicles() == 1) {
    02449     /* When there is only one vehicle, remove the shared order list window. */
    02450     DeleteWindowById(GetWindowClassForVehicleType(this->type), vli.Pack());
    02451     InvalidateVehicleOrder(this->FirstShared(), 0);
    02452   } else if (were_first) {
    02453     /* If we were the first one, update to the new first one.
    02454      * Note: FirstShared() is already the new first */
    02455     InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.Pack(), this->FirstShared()->index | (1U << 31));
    02456   }
    02457
    02458   this->next_shared     = NULL;
    02459   this->previous_shared = NULL;
    02460 }
    02461
    02462 void VehiclesYearlyLoop()
    02463 {
    02464   Vehicle *v;
    02465   FOR_ALL_VEHICLES(v) {
    02466     if (v->IsPrimaryVehicle()) {
    02467       /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
    02468       Money profit = v->GetDisplayProfitThisYear();
    02469       if (v->age >= 730 && profit < 0) {
    02470         if (_settings_client.gui.vehicle_income_warn && v->owner == _local_company) {
    02471           SetDParam(0, v->index);
    02472           SetDParam(1, profit);
    02473           AddVehicleAdviceNewsItem(STR_NEWS_VEHICLE_IS_UNPROFITABLE, v->index);
    02474         }
    02475         AI::NewEvent(v->owner, new ScriptEventVehicleUnprofitable(v->index));
    02476       }
    02477
    02478       v->profit_last_year = v->profit_this_year;
    02479       v->profit_this_year = 0;
    02480       SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    02481     }
    02482   }
    02483   GroupStatistics::UpdateProfits();
    02484   SetWindowClassesDirty(WC_TRAINS_LIST);
    02485   SetWindowClassesDirty(WC_SHIPS_LIST);
    02486   SetWindowClassesDirty(WC_ROADVEH_LIST);
    02487   SetWindowClassesDirty(WC_AIRCRAFT_LIST);
    02488 }
    02489
    02490
    02500 bool CanVehicleUseStation(EngineID engine_type, const Station *st)
    02501 {
    02502   const Engine *e = Engine::GetIfValid(engine_type);
    02503   assert(e != NULL);
    02504
    02505   switch (e->type) {
    02506     case VEH_TRAIN:
    02507       return (st->facilities & FACIL_TRAIN) != 0;
    02508
    02509     case VEH_ROAD:
    02510       /* For road vehicles we need the vehicle to know whether it can actually
    02511        * use the station, but if it doesn't have facilities for RVs it is
    02512        * certainly not possible that the station can be used. */
    02513       return (st->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP)) != 0;
    02514
    02515     case VEH_SHIP:
    02516       return (st->facilities & FACIL_DOCK) != 0;
    02517
    02518     case VEH_AIRCRAFT:
    02519       return (st->facilities & FACIL_AIRPORT) != 0 &&
    02520           (st->airport.GetFTA()->flags & (e->u.air.subtype & AIR_CTOL ? AirportFTAClass::AIRPLANES : AirportFTAClass::HELICOPTERS)) != 0;
    02521
    02522     default:
    02523       return false;
    02524   }
    02525 }
    02526
    02533 bool CanVehicleUseStation(const Vehicle *v, const Station *st)
    02534 {
    02535   if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != NULL;
    02536
    02537   return CanVehicleUseStation(v->engine_type, st);
    02538 }
    02539
    02545 GroundVehicleCache *Vehicle::GetGroundVehicleCache()
    02546 {
    02547   assert(this->IsGroundVehicle());
    02548   if (this->type == VEH_TRAIN) {
    02549     return &Train::From(this)->gcache;
    02550   } else {
    02551     return &RoadVehicle::From(this)->gcache;
    02552   }
    02553 }
    02554
    02560 const GroundVehicleCache *Vehicle::GetGroundVehicleCache() const
    02561 {
    02562   assert(this->IsGroundVehicle());
    02563   if (this->type == VEH_TRAIN) {
    02564     return &Train::From(this)->gcache;
    02565   } else {
    02566     return &RoadVehicle::From(this)->gcache;
    02567   }
    02568 }
    02569
    02575 uint16 &Vehicle::GetGroundVehicleFlags()
    02576 {
    02577   assert(this->IsGroundVehicle());
    02578   if (this->type == VEH_TRAIN) {
    02579     return Train::From(this)->gv_flags;
    02580   } else {
    02581     return RoadVehicle::From(this)->gv_flags;
    02582   }
    02583 }
    02584
    02590 const uint16 &Vehicle::GetGroundVehicleFlags() const
    02591 {
    02592   assert(this->IsGroundVehicle());
    02593   if (this->type == VEH_TRAIN) {
    02594     return Train::From(this)->gv_flags;
    02595   } else {
    02596     return RoadVehicle::From(this)->gv_flags;
    02597   }
    02598 }
    02599
    02608 void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8 num_vehicles)
    02609 {
    02610   if (v->type == VEH_TRAIN) {
    02611     Train *u = Train::From(v);
    02612     /* Only include whole vehicles, so start with the first articulated part */
    02613     u = u->GetFirstEnginePart();
    02614
    02615     /* Include num_vehicles vehicles, not counting articulated parts */
    02616     for (; u != NULL && num_vehicles > 0; num_vehicles--) {
    02617       do {
    02618         /* Include current vehicle in the selection. */
    02619         set.Include(u->index);
    02620
    02621         /* If the vehicle is multiheaded, add the other part too. */
    02622         if (u->IsMultiheaded()) set.Include(u->other_multiheaded_part->index);
    02623
    02624         u = u->Next();
    02625       } while (u != NULL && u->IsArticulatedPart());
    02626     }
    02627   }
    02628 }