vehicle.cpp

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