# vehicle.cpp

Go to the documentation of this file.

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