vehicle.cpp

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