# vehicle.cpp

Go to the documentation of this file.

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