vehicle.cpp

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