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