# 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     MarkAllViewportsDirty(
    01421       min(old_coord.left,   v->coord.left),
    01422       min(old_coord.top,    v->coord.top),
    01423       max(old_coord.right,  v->coord.right) + 1 * ZOOM_LVL_BASE,
    01424       max(old_coord.bottom, v->coord.bottom) + 1 * ZOOM_LVL_BASE
    01425     );
    01426   }
    01427 }
    01428
    01433 void VehicleUpdatePositionAndViewport(Vehicle *v)
    01434 {
    01435   VehicleUpdatePosition(v);
    01436   VehicleUpdateViewport(v, true);
    01437 }
    01438
    01443 void MarkSingleVehicleDirty(const Vehicle *v)
    01444 {
    01445   MarkAllViewportsDirty(v->coord.left, v->coord.top, v->coord.right + 1 * ZOOM_LVL_BASE, v->coord.bottom + 1 * ZOOM_LVL_BASE);
    01446 }
    01447
    01453 GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
    01454 {
    01455   static const int8 _delta_coord[16] = {
    01456     -1,-1,-1, 0, 1, 1, 1, 0, /* x */
    01457     -1, 0, 1, 1, 1, 0,-1,-1, /* y */
    01458   };
    01459
    01460   int x = v->x_pos + _delta_coord[v->direction];
    01461   int y = v->y_pos + _delta_coord[v->direction + 8];
    01462
    01463   GetNewVehiclePosResult gp;
    01464   gp.x = x;
    01465   gp.y = y;
    01466   gp.old_tile = v->tile;
    01467   gp.new_tile = TileVirtXY(x, y);
    01468   return gp;
    01469 }
    01470
    01471 static const Direction _new_direction_table[] = {
    01472   DIR_N,  DIR_NW, DIR_W,
    01473   DIR_NE, DIR_SE, DIR_SW,
    01474   DIR_E,  DIR_SE, DIR_S
    01475 };
    01476
    01477 Direction GetDirectionTowards(const Vehicle *v, int x, int y)
    01478 {
    01479   int i = 0;
    01480
    01481   if (y >= v->y_pos) {
    01482     if (y != v->y_pos) i += 3;
    01483     i += 3;
    01484   }
    01485
    01486   if (x >= v->x_pos) {
    01487     if (x != v->x_pos) i++;
    01488     i++;
    01489   }
    01490
    01491   Direction dir = v->direction;
    01492
    01493   DirDiff dirdiff = DirDifference(_new_direction_table[i], dir);
    01494   if (dirdiff == DIRDIFF_SAME) return dir;
    01495   return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
    01496 }
    01497
    01507 VehicleEnterTileStatus VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
    01508 {
    01509   return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
    01510 }
    01511
    01519 FreeUnitIDGenerator::FreeUnitIDGenerator(VehicleType type, CompanyID owner) : cache(NULL), maxid(0), curid(0)
    01520 {
    01521   /* Find maximum */
    01522   const Vehicle *v;
    01523   FOR_ALL_VEHICLES(v) {
    01524     if (v->type == type && v->owner == owner) {
    01525       this->maxid = max<UnitID>(this->maxid, v->unitnumber);
    01526     }
    01527   }
    01528
    01529   if (this->maxid == 0) return;
    01530
    01531   /* Reserving 'maxid + 2' because we need:
    01532    * - space for the last item (with v->unitnumber == maxid)
    01533    * - one free slot working as loop terminator in FreeUnitIDGenerator::NextID() */
    01534   this->cache = CallocT<bool>(this->maxid + 2);
    01535
    01536   /* Fill the cache */
    01537   FOR_ALL_VEHICLES(v) {
    01538     if (v->type == type && v->owner == owner) {
    01539       this->cache[v->unitnumber] = true;
    01540     }
    01541   }
    01542 }
    01543
    01545 UnitID FreeUnitIDGenerator::NextID()
    01546 {
    01547   if (this->maxid <= this->curid) return ++this->curid;
    01548
    01549   while (this->cache[++this->curid]) { } // it will stop, we reserved more space than needed
    01550
    01551   return this->curid;
    01552 }
    01553
    01559 UnitID GetFreeUnitNumber(VehicleType type)
    01560 {
    01561   /* Check whether it is allowed to build another vehicle. */
    01562   uint max_veh;
    01563   switch (type) {
    01564     case VEH_TRAIN:    max_veh = _settings_game.vehicle.max_trains;   break;
    01565     case VEH_ROAD:     max_veh = _settings_game.vehicle.max_roadveh;  break;
    01566     case VEH_SHIP:     max_veh = _settings_game.vehicle.max_ships;    break;
    01567     case VEH_AIRCRAFT: max_veh = _settings_game.vehicle.max_aircraft; break;
    01568     default: NOT_REACHED();
    01569   }
    01570
    01571   const Company *c = Company::Get(_current_company);
    01572   if (c->group_all[type].num_vehicle >= max_veh) return UINT16_MAX; // Currently already at the limit, no room to make a new one.
    01573
    01574   FreeUnitIDGenerator gen(type, _current_company);
    01575
    01576   return gen.NextID();
    01577 }
    01578
    01579
    01588 bool CanBuildVehicleInfrastructure(VehicleType type)
    01589 {
    01590   assert(IsCompanyBuildableVehicleType(type));
    01591
    01592   if (!Company::IsValidID(_local_company)) return false;
    01593   if (!_settings_client.gui.disable_unsuitable_building) return true;
    01594
    01595   UnitID max;
    01596   switch (type) {
    01597     case VEH_TRAIN:    max = _settings_game.vehicle.max_trains; break;
    01598     case VEH_ROAD:     max = _settings_game.vehicle.max_roadveh; break;
    01599     case VEH_SHIP:     max = _settings_game.vehicle.max_ships; break;
    01600     case VEH_AIRCRAFT: max = _settings_game.vehicle.max_aircraft; break;
    01601     default: NOT_REACHED();
    01602   }
    01603
    01604   /* We can build vehicle infrastructure when we may build the vehicle type */
    01605   if (max > 0) {
    01606     /* Can we actually build the vehicle type? */
    01607     const Engine *e;
    01608     FOR_ALL_ENGINES_OF_TYPE(e, type) {
    01609       if (HasBit(e->company_avail, _local_company)) return true;
    01610     }
    01611     return false;
    01612   }
    01613
    01614   /* We should be able to build infrastructure when we have the actual vehicle type */
    01615   const Vehicle *v;
    01616   FOR_ALL_VEHICLES(v) {
    01617     if (v->owner == _local_company && v->type == type) return true;
    01618   }
    01619
    01620   return false;
    01621 }
    01622
    01623
    01631 LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
    01632 {
    01633   CargoID cargo_type = v == NULL ? (CargoID)CT_INVALID : v->cargo_type;
    01634   const Engine *e = Engine::Get(engine_type);
    01635   switch (e->type) {
    01636     default: NOT_REACHED();
    01637     case VEH_TRAIN:
    01638       if (v != NULL && parent_engine_type != INVALID_ENGINE && (UsesWagonOverride(v) || (v->IsArticulatedPart() && e->u.rail.railveh_type != RAILVEH_WAGON))) {
    01639         /* Wagonoverrides use the colour scheme of the front engine.
    01640          * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */
    01641         engine_type = parent_engine_type;
    01642         e = Engine::Get(engine_type);
    01643         /* Note: Luckily cargo_type is not needed for engines */
    01644       }
    01645
    01646       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01647       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01648       if (e->u.rail.railveh_type == RAILVEH_WAGON) {
    01649         if (!CargoSpec::Get(cargo_type)->is_freight) {
    01650           if (parent_engine_type == INVALID_ENGINE) {
    01651             return LS_PASSENGER_WAGON_STEAM;
    01652           } else {
    01653             switch (RailVehInfo(parent_engine_type)->engclass) {
    01654               default: NOT_REACHED();
    01655               case EC_STEAM:    return LS_PASSENGER_WAGON_STEAM;
    01656               case EC_DIESEL:   return LS_PASSENGER_WAGON_DIESEL;
    01657               case EC_ELECTRIC: return LS_PASSENGER_WAGON_ELECTRIC;
    01658               case EC_MONORAIL: return LS_PASSENGER_WAGON_MONORAIL;
    01659               case EC_MAGLEV:   return LS_PASSENGER_WAGON_MAGLEV;
    01660             }
    01661           }
    01662         } else {
    01663           return LS_FREIGHT_WAGON;
    01664         }
    01665       } else {
    01666         bool is_mu = HasBit(e->info.misc_flags, EF_RAIL_IS_MU);
    01667
    01668         switch (e->u.rail.engclass) {
    01669           default: NOT_REACHED();
    01670           case EC_STEAM:    return LS_STEAM;
    01671           case EC_DIESEL:   return is_mu ? LS_DMU : LS_DIESEL;
    01672           case EC_ELECTRIC: return is_mu ? LS_EMU : LS_ELECTRIC;
    01673           case EC_MONORAIL: return LS_MONORAIL;
    01674           case EC_MAGLEV:   return LS_MAGLEV;
    01675         }
    01676       }
    01677
    01678     case VEH_ROAD:
    01679       /* Always use the livery of the front */
    01680       if (v != NULL && parent_engine_type != INVALID_ENGINE) {
    01681         engine_type = parent_engine_type;
    01682         e = Engine::Get(engine_type);
    01683         cargo_type = v->First()->cargo_type;
    01684       }
    01685       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01686       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01687
    01688       /* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */
    01689       if (HasBit(e->info.misc_flags, EF_ROAD_TRAM)) {
    01690         /* Tram */
    01691         return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
    01692       } else {
    01693         /* Bus or truck */
    01694         return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_BUS : LS_TRUCK;
    01695       }
    01696
    01697     case VEH_SHIP:
    01698       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01699       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01700       return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
    01701
    01702     case VEH_AIRCRAFT:
    01703       switch (e->u.air.subtype) {
    01704         case AIR_HELI: return LS_HELICOPTER;
    01705         case AIR_CTOL: return LS_SMALL_PLANE;
    01706         case AIR_CTOL | AIR_FAST: return LS_LARGE_PLANE;
    01707         default: NOT_REACHED();
    01708       }
    01709   }
    01710 }
    01711
    01721 const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, byte livery_setting)
    01722 {
    01723   const Company *c = Company::Get(company);
    01724   LiveryScheme scheme = LS_DEFAULT;
    01725
    01726   /* The default livery is always available for use, but its in_use flag determines
    01727    * whether any _other_ liveries are in use. */
    01728   if (c->livery[LS_DEFAULT].in_use && (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company))) {
    01729     /* Determine the livery scheme to use */
    01730     scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
    01731
    01732     /* Switch back to the default scheme if the resolved scheme is not in use */
    01733     if (!c->livery[scheme].in_use) scheme = LS_DEFAULT;
    01734   }
    01735
    01736   return &c->livery[scheme];
    01737 }
    01738
    01739
    01740 static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
    01741 {
    01742   PaletteID map = (v != NULL) ? v->colourmap : PAL_NONE;
    01743
    01744   /* Return cached value if any */
    01745   if (map != PAL_NONE) return map;
    01746
    01747   const Engine *e = Engine::Get(engine_type);
    01748
    01749   /* Check if we should use the colour map callback */
    01750   if (HasBit(e->info.callback_mask, CBM_VEHICLE_COLOUR_REMAP)) {
    01751     uint16 callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
    01752     /* Failure means "use the default two-colour" */
    01753     if (callback != CALLBACK_FAILED) {
    01754       assert_compile(PAL_NONE == 0); // Returning 0x4000 (resp. 0xC000) conincidences with default value (PAL_NONE)
    01755       map = GB(callback, 0, 14);
    01756       /* If bit 14 is set, then the company colours are applied to the
    01757        * map else it's returned as-is. */
    01758       if (!HasBit(callback, 14)) {
    01759         /* Update cache */
    01760         if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
    01761         return map;
    01762       }
    01763     }
    01764   }
    01765
    01766   bool twocc = HasBit(e->info.misc_flags, EF_USES_2CC);
    01767
    01768   if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
    01769
    01770   /* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
    01771   if (!Company::IsValidID(company)) return map;
    01772
    01773   const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries);
    01774
    01775   map += livery->colour1;
    01776   if (twocc) map += livery->colour2 * 16;
    01777
    01778   /* Update cache */
    01779   if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
    01780   return map;
    01781 }
    01782
    01789 PaletteID GetEnginePalette(EngineID engine_type, CompanyID company)
    01790 {
    01791   return GetEngineColourMap(engine_type, company, INVALID_ENGINE, NULL);
    01792 }
    01793
    01799 PaletteID GetVehiclePalette(const Vehicle *v)
    01800 {
    01801   if (v->IsGroundVehicle()) {
    01802     return GetEngineColourMap(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v);
    01803   }
    01804
    01805   return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
    01806 }
    01807
    01811 void Vehicle::DeleteUnreachedImplicitOrders()
    01812 {
    01813   if (this->IsGroundVehicle()) {
    01814     uint16 &gv_flags = this->GetGroundVehicleFlags();
    01815     if (HasBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS)) {
    01816       /* Do not delete orders, only skip them */
    01817       ClrBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
    01818       this->cur_implicit_order_index = this->cur_real_order_index;
    01819       InvalidateVehicleOrder(this, 0);
    01820       return;
    01821     }
    01822   }
    01823
    01824   const Order *order = this->GetOrder(this->cur_implicit_order_index);
    01825   while (order != NULL) {
    01826     if (this->cur_implicit_order_index == this->cur_real_order_index) break;
    01827
    01828     if (order->IsType(OT_IMPLICIT)) {
    01829       /* Delete order effectively deletes order, so get the next before deleting it. */
    01830       order = order->next;
    01831       DeleteOrder(this, this->cur_implicit_order_index);
    01832     } else {
    01833       /* Skip non-implicit orders, e.g. service-orders */
    01834       order = order->next;
    01835       this->cur_implicit_order_index++;
    01836     }
    01837
    01838     /* Wrap around */
    01839     if (order == NULL) {
    01840       order = this->GetOrder(0);
    01841       this->cur_implicit_order_index = 0;
    01842     }
    01843   }
    01844 }
    01845
    01850 void Vehicle::BeginLoading()
    01851 {
    01852   assert(IsTileType(this->tile, MP_STATION) || this->type == VEH_SHIP);
    01853
    01854   if (this->current_order.IsType(OT_GOTO_STATION) &&
    01855       this->current_order.GetDestination() == this->last_station_visited) {
    01856     this->DeleteUnreachedImplicitOrders();
    01857
    01858     /* Now both order indices point to the destination station, and we can start loading */
    01859     this->current_order.MakeLoading(true);
    01860     UpdateVehicleTimetable(this, true);
    01861
    01862     /* Furthermore add the Non Stop flag to mark that this station
    01863      * is the actual destination of the vehicle, which is (for example)
    01864      * necessary to be known for HandleTrainLoading to determine
    01865      * whether the train is lost or not; not marking a train lost
    01866      * that arrives at random stations is bad. */
    01867     this->current_order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
    01868
    01869   } else {
    01870     /* We weren't scheduled to stop here. Insert an implicit order
    01871      * to show that we are stopping here, but only do that if the order
    01872      * list isn't empty.
    01873      * While only groundvehicles have implicit orders, e.g. aircraft might still enter
    01874      * the 'wrong' terminal when skipping orders etc. */
    01875     Order *in_list = this->GetOrder(this->cur_implicit_order_index);
    01876     if (this->IsGroundVehicle() && in_list != NULL &&
    01877         (!in_list->IsType(OT_IMPLICIT) ||
    01878         in_list->GetDestination() != this->last_station_visited)) {
    01879       bool suppress_implicit_orders = HasBit(this->GetGroundVehicleFlags(), GVF_SUPPRESS_IMPLICIT_ORDERS);
    01880       /* Do not create consecutive duplicates of implicit orders */
    01881       Order *prev_order = this->cur_implicit_order_index > 0 ? this->GetOrder(this->cur_implicit_order_index - 1) : (this->GetNumOrders() > 1 ? this->GetLastOrder() : NULL);
    01882       if (prev_order == NULL ||
    01883           (!prev_order->IsType(OT_IMPLICIT) && !prev_order->IsType(OT_GOTO_STATION)) ||
    01884           prev_order->GetDestination() != this->last_station_visited) {
    01885
    01886         /* Prefer deleting implicit orders instead of inserting new ones,
    01887          * so test whether the right order follows later */
    01888         int target_index = this->cur_implicit_order_index;
    01889         bool found = false;
    01890         while (target_index != this->cur_real_order_index) {
    01891           const Order *order = this->GetOrder(target_index);
    01892           if (order->IsType(OT_IMPLICIT) && order->GetDestination() == this->last_station_visited) {
    01893             found = true;
    01894             break;
    01895           }
    01896           target_index++;
    01897           if (target_index >= this->orders.list->GetNumOrders()) target_index = 0;
    01898           assert(target_index != this->cur_implicit_order_index); // infinite loop?
    01899         }
    01900
    01901         if (found) {
    01902           if (suppress_implicit_orders) {
    01903             /* Skip to the found order */
    01904             this->cur_implicit_order_index = target_index;
    01905             InvalidateVehicleOrder(this, 0);
    01906           } else {
    01907             /* Delete all implicit orders up to the station we just reached */
    01908             const Order *order = this->GetOrder(this->cur_implicit_order_index);
    01909             while (!order->IsType(OT_IMPLICIT) || order->GetDestination() != this->last_station_visited) {
    01910               if (order->IsType(OT_IMPLICIT)) {
    01911                 /* Delete order effectively deletes order, so get the next before deleting it. */
    01912                 order = order->next;
    01913                 DeleteOrder(this, this->cur_implicit_order_index);
    01914               } else {
    01915                 /* Skip non-implicit orders, e.g. service-orders */
    01916                 order = order->next;
    01917                 this->cur_implicit_order_index++;
    01918               }
    01919
    01920               /* Wrap around */
    01921               if (order == NULL) {
    01922                 order = this->GetOrder(0);
    01923                 this->cur_implicit_order_index = 0;
    01924               }
    01925               assert(order != NULL);
    01926             }
    01927           }
    01928         } else if (!suppress_implicit_orders && this->orders.list->GetNumOrders() < MAX_VEH_ORDER_ID && Order::CanAllocateItem()) {
    01929           /* Insert new implicit order */
    01930           Order *implicit_order = new Order();
    01931           implicit_order->MakeImplicit(this->last_station_visited);
    01932           InsertOrder(this, implicit_order, this->cur_implicit_order_index);
    01933           if (this->cur_implicit_order_index > 0) --this->cur_implicit_order_index;
    01934
    01935           /* InsertOrder disabled creation of implicit orders for all vehicles with the same implicit order.
    01936            * Reenable it for this vehicle */
    01937           uint16 &gv_flags = this->GetGroundVehicleFlags();
    01938           ClrBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
    01939         }
    01940       }
    01941     }
    01942     this->current_order.MakeLoading(false);
    01943   }
    01944
    01945   if (this->last_loading_station != INVALID_STATION &&
    01946       this->last_loading_station != this->last_station_visited &&
    01947       ((this->current_order.GetLoadType() & OLFB_NO_LOAD) == 0 ||
    01948       (this->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0)) {
    01949     IncreaseStats(Station::Get(this->last_loading_station), this, this->last_station_visited);
    01950   }
    01951
    01952   PrepareUnload(this);
    01953
    01954   SetWindowDirty(GetWindowClassForVehicleType(this->type), this->owner);
    01955   SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
    01956   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
    01957   SetWindowDirty(WC_STATION_VIEW, this->last_station_visited);
    01958
    01959   Station::Get(this->last_station_visited)->MarkTilesDirty(true);
    01960   this->cur_speed = 0;
    01961   this->MarkDirty();
    01962 }
    01963
    01968 void Vehicle::CancelReservation(StationID next, Station *st)
    01969 {
    01970   for (Vehicle *v = this; v != NULL; v = v->next) {
    01971     VehicleCargoList &cargo = v->cargo;
    01972     if (cargo.ReservedCount() > 0) {
    01973       DEBUG(misc, 1, "cancelling cargo reservation");
    01974       GoodsEntry &ge = st->goods[v->cargo_type];
    01975       cargo.Unreserve(next, &ge.cargo);
    01976       SetBit(ge.acceptance_pickup, GoodsEntry::GES_PICKUP);
    01977     }
    01978   }
    01979 }
    01980
    01985 void Vehicle::LeaveStation()
    01986 {
    01987   assert(this->current_order.IsType(OT_LOADING));
    01988
    01989   delete this->cargo_payment;
    01990
    01991   /* Only update the timetable if the vehicle was supposed to stop here. */
    01992   if (this->current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE) UpdateVehicleTimetable(this, false);
    01993
    01994   if ((this->current_order.GetLoadType() & OLFB_NO_LOAD) == 0 ||
    01995       (this->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) {
    01996     if (this->current_order.CanLeaveWithCargo(this->last_loading_station != INVALID_STATION)) {
    01997       /* Refresh next hop stats to make sure we've done that at least once
    01998        * during the stop and that refit_cap == cargo_cap for each vehicle in
    01999        * the consist.
    02000        */
    02001       this->RefreshNextHopsStats();
    02002
    02003       /* if the vehicle could load here or could stop with cargo loaded set the last loading station */
    02004       this->last_loading_station = this->last_station_visited;
    02005     } else {
    02006       /* if the vehicle couldn't load and had to unload or transfer everything
    02007        * set the last loading station to invalid as it will leave empty.
    02008        */
    02009       this->last_loading_station = INVALID_STATION;
    02010     }
    02011   }
    02012
    02013   this->current_order.MakeLeaveStation();
    02014   Station *st = Station::Get(this->last_station_visited);
    02015   this->CancelReservation(INVALID_STATION, st);
    02016   st->loading_vehicles.remove(this);
    02017
    02018   HideFillingPercent(&this->fill_percent_te_id);
    02019
    02020   if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) {
    02021     /* Trigger station animation (trains only) */
    02022     if (IsTileType(this->tile, MP_STATION)) TriggerStationAnimation(st, this->tile, SAT_TRAIN_DEPARTS);
    02023
    02024     SetBit(Train::From(this)->flags, VRF_LEAVING_STATION);
    02025   }
    02026 }
    02027
    02034 void Vehicle::RefreshNextHopsStats()
    02035 {
    02036   /* Assemble list of capacities and set last loading stations to 0. */
    02037   SmallMap<CargoID, uint, 1> capacities;
    02038   for (Vehicle *v = this; v != NULL; v = v->Next()) {
    02039     v->refit_cap = v->cargo_cap;
    02040     if (v->refit_cap == 0) continue;
    02041     SmallPair<CargoID, uint> *i = capacities.Find(v->cargo_type);
    02042     if (i == capacities.End()) {
    02043       /* Braindead smallmap not providing a good method for that. */
    02044       i = capacities.Append();
    02045       i->first = v->cargo_type;
    02046       i->second = v->cargo_cap;
    02047     } else {
    02048       i->second += v->cargo_cap;
    02049     }
    02050   }
    02051
    02052   /* If orders were deleted while loading, we're done here.*/
    02053   if (this->orders.list == NULL) return;
    02054
    02055   uint hops = 0;
    02056   const Order *first = this->orders.list->GetNextStoppingOrder(this,
    02057       this->GetOrder(this->cur_implicit_order_index), hops);
    02058   const Order *cur = first;
    02059   const Order *next = first;
    02060   while (next != NULL && cur->CanLeaveWithCargo(true)) {
    02061     next = this->orders.list->GetNextStoppingOrder(this,
    02062         this->orders.list->GetNext(next), ++hops);
    02063     if (next == NULL) break;
    02064
    02065     if (next->IsType(OT_GOTO_DEPOT)) {
    02066       /* handle refit by dropping some vehicles. */
    02067       CargoID new_cid = next->GetRefitCargo();
    02068       byte new_subtype = next->GetRefitSubtype();
    02069       for (Vehicle *v = this; v != NULL; v = v->Next()) {
    02070         const Engine *e = Engine::Get(v->engine_type);
    02071         if (!HasBit(e->info.refit_mask, new_cid)) continue;
    02072
    02073         /* Back up the vehicle's cargo type */
    02074         CargoID temp_cid = v->cargo_type;
    02075         byte temp_subtype = v->cargo_subtype;
    02076         v->cargo_type = new_cid;
    02077         v->cargo_subtype = new_subtype;
    02078
    02079         uint16 mail_capacity = 0;
    02080         uint amount = e->DetermineCapacity(v, &mail_capacity);
    02081
    02082         /* Restore the original cargo type */
    02083         v->cargo_type = temp_cid;
    02084         v->cargo_subtype = temp_subtype;
    02085
    02086         /* Skip on next refit. */
    02087         if (new_cid != v->cargo_type && v->refit_cap > 0) {
    02088           capacities[v->cargo_type] -= v->refit_cap;
    02089           v->refit_cap = 0;
    02090         } else if (amount < v->refit_cap) {
    02091           capacities[v->cargo_type] -= v->refit_cap - amount;
    02092           v->refit_cap = amount;
    02093         }
    02094
    02095         /* Special case for aircraft with mail. */
    02096         if (v->type == VEH_AIRCRAFT) {
    02097           Vehicle *u = v->Next();
    02098           if (mail_capacity < u->refit_cap) {
    02099             capacities[u->cargo_type] -= u->refit_cap - mail_capacity;
    02100             u->refit_cap = mail_capacity;
    02101           }
    02102           break; // aircraft have only one vehicle
    02103         }
    02104         if (v->type == VEH_SHIP) break; // ships too
    02105       }
    02106     } else {
    02107       StationID next_station = next->GetDestination();
    02108       Station *st = Station::GetIfValid(cur->GetDestination());
    02109       if (st != NULL && next_station != INVALID_STATION && next_station != st->index) {
    02110         for (const SmallPair<CargoID, uint> *i = capacities.Begin(); i != capacities.End(); ++i) {
    02111           /* Refresh the link and give it a minimum capacity. */
    02112           if (i->second > 0) IncreaseStats(st, i->first, next_station, i->second, UINT_MAX);
    02113         }
    02114       }
    02115       cur = next;
    02116       if (cur == first) break;
    02117     }
    02118   }
    02119
    02120   for (Vehicle *v = this; v != NULL; v = v->Next()) v->refit_cap = v->cargo_cap;
    02121 }
    02122
    02128 void Vehicle::HandleLoading(bool mode)
    02129 {
    02130   switch (this->current_order.GetType()) {
    02131     case OT_LOADING: {
    02132       uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0);
    02133
    02134       /* Not the first call for this tick, or still loading */
    02135       if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || this->current_order_time < wait_time) return;
    02136
    02137       this->PlayLeaveStationSound();
    02138
    02139       this->LeaveStation();
    02140
    02141       /* Only advance to next order if we just loaded at the current one */
    02142       const Order *order = this->GetOrder(this->cur_implicit_order_index);
    02143       if (order == NULL ||
    02144           (!order->IsType(OT_IMPLICIT) && !order->IsType(OT_GOTO_STATION)) ||
    02145           order->GetDestination() != this->last_station_visited) {
    02146         return;
    02147       }
    02148       break;
    02149     }
    02150
    02151     case OT_DUMMY: break;
    02152
    02153     default: return;
    02154   }
    02155
    02156   this->IncrementImplicitOrderIndex();
    02157 }
    02158
    02163 void Vehicle::GetConsistFreeCapacities(SmallMap<CargoID, uint> &capacities) const
    02164 {
    02165   for (const Vehicle *v = this; v != NULL; v = v->Next()) {
    02166     if (v->cargo_cap == 0) continue;
    02167     SmallPair<CargoID, uint> *pair = capacities.Find(v->cargo_type);
    02168     if (pair == capacities.End()) {
    02169       pair = capacities.Append();
    02170       pair->first = v->cargo_type;
    02171       pair->second = v->cargo_cap - v->cargo.Count();
    02172     } else {
    02173       pair->second += v->cargo_cap - v->cargo.Count();
    02174     }
    02175   }
    02176 }
    02177
    02178 uint Vehicle::GetConsistTotalCapacity() const
    02179 {
    02180   uint result = 0;
    02181   for (const Vehicle *v = this; v != NULL; v = v->Next()) {
    02182     result += v->cargo_cap;
    02183   }
    02184   return result;
    02185 }
    02186
    02193 CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command)
    02194 {
    02195   CommandCost ret = CheckOwnership(this->owner);
    02196   if (ret.Failed()) return ret;
    02197
    02198   if (this->vehstatus & VS_CRASHED) return CMD_ERROR;
    02199   if (this->IsStoppedInDepot()) return CMD_ERROR;
    02200
    02201   if (this->current_order.IsType(OT_GOTO_DEPOT)) {
    02202     bool halt_in_depot = (this->current_order.GetDepotActionType() & ODATFB_HALT) != 0;
    02203     if (!!(command & DEPOT_SERVICE) == halt_in_depot) {
    02204       /* We called with a different DEPOT_SERVICE setting.
    02205        * Now we change the setting to apply the new one and let the vehicle head for the same depot.
    02206        * Note: the if is (true for requesting service == true for ordered to stop in depot)          */
    02207       if (flags & DC_EXEC) {
    02208         this->current_order.SetDepotOrderType(ODTF_MANUAL);
    02209         this->current_order.SetDepotActionType(halt_in_depot ? ODATF_SERVICE_ONLY : ODATFB_HALT);
    02210         SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
    02211       }
    02212       return CommandCost();
    02213     }
    02214
    02215     if (command & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
    02216     if (flags & DC_EXEC) {
    02217       /* If the orders to 'goto depot' are in the orders list (forced servicing),
    02218        * then skip to the next order; effectively cancelling this forced service */
    02219       if (this->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) this->IncrementRealOrderIndex();
    02220
    02221       if (this->IsGroundVehicle()) {
    02222         uint16 &gv_flags = this->GetGroundVehicleFlags();
    02223         SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
    02224       }
    02225
    02226       this->current_order.MakeDummy();
    02227       SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
    02228     }
    02229     return CommandCost();
    02230   }
    02231
    02232   TileIndex location;
    02233   DestinationID destination;
    02234   bool reverse;
    02235   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};
    02236   if (!this->FindClosestDepot(&location, &destination, &reverse)) return_cmd_error(no_depot[this->type]);
    02237
    02238   if (flags & DC_EXEC) {
    02239     if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
    02240
    02241     if (this->IsGroundVehicle()) {
    02242       uint16 &gv_flags = this->GetGroundVehicleFlags();
    02243       SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
    02244     }
    02245
    02246     this->dest_tile = location;
    02247     this->current_order.MakeGoToDepot(destination, ODTF_MANUAL);
    02248     if (!(command & DEPOT_SERVICE)) this->current_order.SetDepotActionType(ODATFB_HALT);
    02249     SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
    02250
    02251     /* If there is no depot in front, reverse automatically (trains only) */
    02252     if (this->type == VEH_TRAIN && reverse) DoCommand(this->tile, this->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
    02253
    02254     if (this->type == VEH_AIRCRAFT) {
    02255       Aircraft *a = Aircraft::From(this);
    02256       if (a->state == FLYING && a->targetairport != destination) {
    02257         /* The aircraft is now heading for a different hangar than the next in the orders */
    02258         extern void AircraftNextAirportPos_and_Order(Aircraft *a);
    02259         AircraftNextAirportPos_and_Order(a);
    02260       }
    02261     }
    02262   }
    02263
    02264   return CommandCost();
    02265
    02266 }
    02267
    02272 void Vehicle::UpdateVisualEffect(bool allow_power_change)
    02273 {
    02274   bool powered_before = HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
    02275   const Engine *e = this->GetEngine();
    02276
    02277   /* Evaluate properties */
    02278   byte visual_effect;
    02279   switch (e->type) {
    02280     case VEH_TRAIN: visual_effect = e->u.rail.visual_effect; break;
    02281     case VEH_ROAD:  visual_effect = e->u.road.visual_effect; break;
    02282     case VEH_SHIP:  visual_effect = e->u.ship.visual_effect; break;
    02283     default:        visual_effect = 1 << VE_DISABLE_EFFECT;  break;
    02284   }
    02285
    02286   /* Check powered wagon / visual effect callback */
    02287   if (HasBit(e->info.callback_mask, CBM_VEHICLE_VISUAL_EFFECT)) {
    02288     uint16 callback = GetVehicleCallback(CBID_VEHICLE_VISUAL_EFFECT, 0, 0, this->engine_type, this);
    02289
    02290     if (callback != CALLBACK_FAILED) {
    02291       if (callback >= 0x100 && e->GetGRF()->grf_version >= 8) ErrorUnknownCallbackResult(e->GetGRFID(), CBID_VEHICLE_VISUAL_EFFECT, callback);
    02292
    02293       callback = GB(callback, 0, 8);
    02294       /* Avoid accidentally setting 'visual_effect' to the default value
    02295        * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
    02296       if (callback == VE_DEFAULT) {
    02297         assert(HasBit(callback, VE_DISABLE_EFFECT));
    02298         SB(callback, VE_TYPE_START, VE_TYPE_COUNT, 0);
    02299       }
    02300       visual_effect = callback;
    02301     }
    02302   }
    02303
    02304   /* Apply default values */
    02305   if (visual_effect == VE_DEFAULT ||
    02306       (!HasBit(visual_effect, VE_DISABLE_EFFECT) && GB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT) == VE_TYPE_DEFAULT)) {
    02307     /* Only train engines have default effects.
    02308      * Note: This is independent of whether the engine is a front engine or articulated part or whatever. */
    02309     if (e->type != VEH_TRAIN || e->u.rail.railveh_type == RAILVEH_WAGON || !IsInsideMM(e->u.rail.engclass, EC_STEAM, EC_MONORAIL)) {
    02310       if (visual_effect == VE_DEFAULT) {
    02311         visual_effect = 1 << VE_DISABLE_EFFECT;
    02312       } else {
    02313         SetBit(visual_effect, VE_DISABLE_EFFECT);
    02314       }
    02315     } else {
    02316       if (visual_effect == VE_DEFAULT) {
    02317         /* Also set the offset */
    02318         visual_effect = (VE_OFFSET_CENTRE - (e->u.rail.engclass == EC_STEAM ? 4 : 0)) << VE_OFFSET_START;
    02319       }
    02320       SB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT, e->u.rail.engclass - EC_STEAM + VE_TYPE_STEAM);
    02321     }
    02322   }
    02323
    02324   this->vcache.cached_vis_effect = visual_effect;
    02325
    02326   if (!allow_power_change && powered_before != HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
    02327     ToggleBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
    02328     ShowNewGrfVehicleError(this->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_POWERED_WAGON, GBUG_VEH_POWERED_WAGON, false);
    02329   }
    02330 }
    02331
    02332 static const int8 _vehicle_smoke_pos[8] = {
    02333   1, 1, 1, 0, -1, -1, -1, 0
    02334 };
    02335
    02340 void Vehicle::ShowVisualEffect() const
    02341 {
    02342   assert(this->IsPrimaryVehicle());
    02343   bool sound = false;
    02344
    02345   /* Do not show any smoke when:
    02346    * - vehicle smoke is disabled by the player
    02347    * - the vehicle is slowing down or stopped (by the player)
    02348    * - the vehicle is moving very slowly
    02349    */
    02350   if (_settings_game.vehicle.smoke_amount == 0 ||
    02351       this->vehstatus & (VS_TRAIN_SLOWING | VS_STOPPED) ||
    02352       this->cur_speed < 2) {
    02353     return;
    02354   }
    02355
    02356   uint max_speed = this->vcache.cached_max_speed;
    02357   if (this->type == VEH_TRAIN) {
    02358     const Train *t = Train::From(this);
    02359     /* For trains, do not show any smoke when:
    02360      * - the train is reversing
    02361      * - is entering a station with an order to stop there and its speed is equal to maximum station entering speed
    02362      */
    02363     if (HasBit(t->flags, VRF_REVERSING) ||
    02364         (IsRailStationTile(t->tile) && t->IsFrontEngine() && t->current_order.ShouldStopAtStation(t, GetStationIndex(t->tile)) &&
    02365         t->cur_speed >= t->Train::GetCurrentMaxSpeed())) {
    02366       return;
    02367     }
    02368
    02369     max_speed = min(max_speed, t->gcache.cached_max_track_speed);
    02370     max_speed = min(max_speed, this->current_order.max_speed);
    02371   }
    02372   if (this->type == VEH_ROAD || this->type == VEH_SHIP) max_speed = min(max_speed, this->current_order.max_speed * 2);
    02373
    02374   const Vehicle *v = this;
    02375
    02376   do {
    02377     int effect_offset = GB(v->vcache.cached_vis_effect, VE_OFFSET_START, VE_OFFSET_COUNT) - VE_OFFSET_CENTRE;
    02378     byte effect_type = GB(v->vcache.cached_vis_effect, VE_TYPE_START, VE_TYPE_COUNT);
    02379     bool disable_effect = HasBit(v->vcache.cached_vis_effect, VE_DISABLE_EFFECT);
    02380
    02381     /* Show no smoke when:
    02382      * - Smoke has been disabled for this vehicle
    02383      * - The vehicle is not visible
    02384      * - The vehicle is under a bridge
    02385      * - The vehicle is on a depot tile
    02386      * - The vehicle is on a tunnel tile
    02387      * - The vehicle is a train engine that is currently unpowered */
    02388     if (disable_effect ||
    02389         v->vehstatus & VS_HIDDEN ||
    02390         (MayHaveBridgeAbove(v->tile) && IsBridgeAbove(v->tile)) ||
    02391         IsDepotTile(v->tile) ||
    02392         IsTunnelTile(v->tile) ||
    02393         (v->type == VEH_TRAIN &&
    02394         !HasPowerOnRail(Train::From(v)->railtype, GetTileRailType(v->tile)))) {
    02395       continue;
    02396     }
    02397
    02398     /* The effect offset is relative to a point 4 units behind the vehicle's
    02399      * front (which is the center of an 8/8 vehicle). Shorter vehicles need a
    02400      * correction factor. */
    02401     if (v->type == VEH_TRAIN) effect_offset += (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
    02402
    02403     int x = _vehicle_smoke_pos[v->direction] * effect_offset;
    02404     int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
    02405
    02406     if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) {
    02407       x = -x;
    02408       y = -y;
    02409     }
    02410
    02411     switch (effect_type) {
    02412       case VE_TYPE_STEAM:
    02413         /* Steam smoke - amount is gradually falling until vehicle reaches its maximum speed, after that it's normal.
    02414          * Details: while vehicle's current speed is gradually increasing, steam plumes' density decreases by one third each
    02415          * third of its maximum speed spectrum. Steam emission finally normalises at very close to vehicle's maximum speed.
    02416          * REGULATION:
    02417          * - instead of 1, 4 / 2^smoke_amount (max. 2) is used to provide sufficient regulation to steam puffs' amount. */
    02418         if (GB(v->tick_counter, 0, ((4 >> _settings_game.vehicle.smoke_amount) + ((this->cur_speed * 3) / max_speed))) == 0) {
    02419           CreateEffectVehicleRel(v, x, y, 10, EV_STEAM_SMOKE);
    02420           sound = true;
    02421         }
    02422         break;
    02423
    02424       case VE_TYPE_DIESEL: {
    02425         /* Diesel smoke - thicker when vehicle is starting, gradually subsiding till it reaches its maximum speed
    02426          * when smoke emission stops.
    02427          * Details: Vehicle's (max.) speed spectrum is divided into 32 parts. When max. speed is reached, chance for smoke
    02428          * emission erodes by 32 (1/4). For trains, power and weight come in handy too to either increase smoke emission in
    02429          * 6 steps (1000HP each) if the power is low or decrease smoke emission in 6 steps (512 tonnes each) if the train
    02430          * isn't overweight. Power and weight contributions are expressed in a way that neither extreme power, nor
    02431          * extreme weight can ruin the balance (e.g. FreightWagonMultiplier) in the formula. When the vehicle reaches
    02432          * maximum speed no diesel_smoke is emitted.
    02433          * REGULATION:
    02434          * - up to which speed a diesel vehicle is emitting smoke (with reduced/small setting only until 1/2 of max_speed),
    02435          * - in Chance16 - the last value is 512 / 2^smoke_amount (max. smoke when 128 = smoke_amount of 2). */
    02436         int power_weight_effect = 0;
    02437         if (v->type == VEH_TRAIN) {
    02438           power_weight_effect = (32 >> (Train::From(this)->gcache.cached_power >> 10)) - (32 >> (Train::From(this)->gcache.cached_weight >> 9));
    02439         }
    02440         if (this->cur_speed < (max_speed >> (2 >> _settings_game.vehicle.smoke_amount)) &&
    02441             Chance16((64 - ((this->cur_speed << 5) / max_speed) + power_weight_effect), (512 >> _settings_game.vehicle.smoke_amount))) {
    02442           CreateEffectVehicleRel(v, x, y, 10, EV_DIESEL_SMOKE);
    02443           sound = true;
    02444         }
    02445         break;
    02446       }
    02447
    02448       case VE_TYPE_ELECTRIC:
    02449         /* Electric train's spark - more often occurs when train is departing (more load)
    02450          * Details: Electric locomotives are usually at least twice as powerful as their diesel counterparts, so spark
    02451          * emissions are kept simple. Only when starting, creating huge force are sparks more likely to happen, but when
    02452          * reaching its max. speed, quarter by quarter of it, chance decreases untill the usuall 2,22% at train's top speed.
    02453          * REGULATION:
    02454          * - in Chance16 the last value is 360 / 2^smoke_amount (max. sparks when 90 = smoke_amount of 2). */
    02455         if (GB(v->tick_counter, 0, 2) == 0 &&
    02456             Chance16((6 - ((this->cur_speed << 2) / max_speed)), (360 >> _settings_game.vehicle.smoke_amount))) {
    02457           CreateEffectVehicleRel(v, x, y, 10, EV_ELECTRIC_SPARK);
    02458           sound = true;
    02459         }
    02460         break;
    02461
    02462       default:
    02463         break;
    02464     }
    02465   } while ((v = v->Next()) != NULL);
    02466
    02467   if (sound) PlayVehicleSound(this, VSE_VISUAL_EFFECT);
    02468 }
    02469
    02474 void Vehicle::SetNext(Vehicle *next)
    02475 {
    02476   assert(this != next);
    02477
    02478   if (this->next != NULL) {
    02479     /* We had an old next vehicle. Update the first and previous pointers */
    02480     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
    02481       v->first = this->next;
    02482     }
    02483     this->next->previous = NULL;
    02484   }
    02485
    02486   this->next = next;
    02487
    02488   if (this->next != NULL) {
    02489     /* A new next vehicle. Update the first and previous pointers */
    02490     if (this->next->previous != NULL) this->next->previous->next = NULL;
    02491     this->next->previous = this;
    02492     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
    02493       v->first = this->first;
    02494     }
    02495   }
    02496 }
    02497
    02503 void Vehicle::AddToShared(Vehicle *shared_chain)
    02504 {
    02505   assert(this->previous_shared == NULL && this->next_shared == NULL);
    02506
    02507   if (shared_chain->orders.list == NULL) {
    02508     assert(shared_chain->previous_shared == NULL);
    02509     assert(shared_chain->next_shared == NULL);
    02510     this->orders.list = shared_chain->orders.list = new OrderList(NULL, shared_chain);
    02511   }
    02512
    02513   this->next_shared     = shared_chain->next_shared;
    02514   this->previous_shared = shared_chain;
    02515
    02516   shared_chain->next_shared = this;
    02517
    02518   if (this->next_shared != NULL) this->next_shared->previous_shared = this;
    02519
    02520   shared_chain->orders.list->AddVehicle(this);
    02521 }
    02522
    02526 void Vehicle::RemoveFromShared()
    02527 {
    02528   /* Remember if we were first and the old window number before RemoveVehicle()
    02529    * as this changes first if needed. */
    02530   bool were_first = (this->FirstShared() == this);
    02531   VehicleListIdentifier vli(VL_SHARED_ORDERS, this->type, this->owner, this->FirstShared()->index);
    02532
    02533   this->orders.list->RemoveVehicle(this);
    02534
    02535   if (!were_first) {
    02536     /* We are not the first shared one, so only relink our previous one. */
    02537     this->previous_shared->next_shared = this->NextShared();
    02538   }
    02539
    02540   if (this->next_shared != NULL) this->next_shared->previous_shared = this->previous_shared;
    02541
    02542
    02543   if (this->orders.list->GetNumVehicles() == 1) {
    02544     /* When there is only one vehicle, remove the shared order list window. */
    02545     DeleteWindowById(GetWindowClassForVehicleType(this->type), vli.Pack());
    02546     InvalidateVehicleOrder(this->FirstShared(), 0);
    02547   } else if (were_first) {
    02548     /* If we were the first one, update to the new first one.
    02549      * Note: FirstShared() is already the new first */
    02550     InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.Pack(), this->FirstShared()->index | (1U << 31));
    02551   }
    02552
    02553   this->next_shared     = NULL;
    02554   this->previous_shared = NULL;
    02555 }
    02556
    02557 void VehiclesYearlyLoop()
    02558 {
    02559   Vehicle *v;
    02560   FOR_ALL_VEHICLES(v) {
    02561     if (v->IsPrimaryVehicle()) {
    02562       /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
    02563       Money profit = v->GetDisplayProfitThisYear();
    02564       if (v->age >= 730 && profit < 0) {
    02565         if (_settings_client.gui.vehicle_income_warn && v->owner == _local_company) {
    02566           SetDParam(0, v->index);
    02567           SetDParam(1, profit);
    02568           AddVehicleNewsItem(
    02569             STR_NEWS_VEHICLE_IS_UNPROFITABLE,
    02570             NS_ADVICE,
    02571             v->index
    02572           );
    02573         }
    02574         AI::NewEvent(v->owner, new ScriptEventVehicleUnprofitable(v->index));
    02575       }
    02576
    02577       v->profit_last_year = v->profit_this_year;
    02578       v->profit_this_year = 0;
    02579       SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    02580     }
    02581   }
    02582   GroupStatistics::UpdateProfits();
    02583   SetWindowClassesDirty(WC_TRAINS_LIST);
    02584   SetWindowClassesDirty(WC_SHIPS_LIST);
    02585   SetWindowClassesDirty(WC_ROADVEH_LIST);
    02586   SetWindowClassesDirty(WC_AIRCRAFT_LIST);
    02587 }
    02588
    02589
    02599 bool CanVehicleUseStation(EngineID engine_type, const Station *st)
    02600 {
    02601   const Engine *e = Engine::GetIfValid(engine_type);
    02602   assert(e != NULL);
    02603
    02604   switch (e->type) {
    02605     case VEH_TRAIN:
    02606       return (st->facilities & FACIL_TRAIN) != 0;
    02607
    02608     case VEH_ROAD:
    02609       /* For road vehicles we need the vehicle to know whether it can actually
    02610        * use the station, but if it doesn't have facilities for RVs it is
    02611        * certainly not possible that the station can be used. */
    02612       return (st->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP)) != 0;
    02613
    02614     case VEH_SHIP:
    02615       return (st->facilities & FACIL_DOCK) != 0;
    02616
    02617     case VEH_AIRCRAFT:
    02618       return (st->facilities & FACIL_AIRPORT) != 0 &&
    02619           (st->airport.GetFTA()->flags & (e->u.air.subtype & AIR_CTOL ? AirportFTAClass::AIRPLANES : AirportFTAClass::HELICOPTERS)) != 0;
    02620
    02621     default:
    02622       return false;
    02623   }
    02624 }
    02625
    02632 bool CanVehicleUseStation(const Vehicle *v, const Station *st)
    02633 {
    02634   if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != NULL;
    02635
    02636   return CanVehicleUseStation(v->engine_type, st);
    02637 }
    02638
    02644 GroundVehicleCache *Vehicle::GetGroundVehicleCache()
    02645 {
    02646   assert(this->IsGroundVehicle());
    02647   if (this->type == VEH_TRAIN) {
    02648     return &Train::From(this)->gcache;
    02649   } else {
    02650     return &RoadVehicle::From(this)->gcache;
    02651   }
    02652 }
    02653
    02659 const GroundVehicleCache *Vehicle::GetGroundVehicleCache() const
    02660 {
    02661   assert(this->IsGroundVehicle());
    02662   if (this->type == VEH_TRAIN) {
    02663     return &Train::From(this)->gcache;
    02664   } else {
    02665     return &RoadVehicle::From(this)->gcache;
    02666   }
    02667 }
    02668
    02674 uint16 &Vehicle::GetGroundVehicleFlags()
    02675 {
    02676   assert(this->IsGroundVehicle());
    02677   if (this->type == VEH_TRAIN) {
    02678     return Train::From(this)->gv_flags;
    02679   } else {
    02680     return RoadVehicle::From(this)->gv_flags;
    02681   }
    02682 }
    02683
    02689 const uint16 &Vehicle::GetGroundVehicleFlags() const
    02690 {
    02691   assert(this->IsGroundVehicle());
    02692   if (this->type == VEH_TRAIN) {
    02693     return Train::From(this)->gv_flags;
    02694   } else {
    02695     return RoadVehicle::From(this)->gv_flags;
    02696   }
    02697 }
    02698
    02707 void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8 num_vehicles)
    02708 {
    02709   if (v->type == VEH_TRAIN) {
    02710     Train *u = Train::From(v);
    02711     /* Only include whole vehicles, so start with the first articulated part */
    02712     u = u->GetFirstEnginePart();
    02713
    02714     /* Include num_vehicles vehicles, not counting articulated parts */
    02715     for (; u != NULL && num_vehicles > 0; num_vehicles--) {
    02716       do {
    02717         /* Include current vehicle in the selection. */
    02718         set.Include(u->index);
    02719
    02720         /* If the vehicle is multiheaded, add the other part too. */
    02721         if (u->IsMultiheaded()) set.Include(u->other_multiheaded_part->index);
    02722
    02723         u = u->Next();
    02724       } while (u != NULL && u->IsArticulatedPart());
    02725     }
    02726   }
    02727 }