# vehicle.cpp

Go to the documentation of this file.

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