# vehicle.cpp

Go to the documentation of this file.

    00001 /* $Id: vehicle.cpp 23740 2012-01-03 21:32:51Z rubidium $ */
    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::Get(this->last_station_visited)->loading_vehicles.remove(this);
    00715
    00716     HideFillingPercent(&this->fill_percent_te_id);
    00717
    00718     delete this->cargo_payment;
    00719   }
    00720
    00721   if (this->IsEngineCountable()) {
    00722     GroupStatistics::CountEngine(this, -1);
    00723     if (this->IsPrimaryVehicle()) GroupStatistics::CountVehicle(this, -1);
    00724     GroupStatistics::UpdateAutoreplace(this->owner);
    00725
    00726     if (this->owner == _local_company) InvalidateAutoreplaceWindow(this->engine_type, this->group_id);
    00727     DeleteGroupHighlightOfVehicle(this);
    00728   }
    00729
    00730   if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) {
    00731     Aircraft *a = Aircraft::From(this);
    00732     Station *st = GetTargetAirportIfValid(a);
    00733     if (st != NULL) {
    00734       const AirportFTA *layout = st->airport.GetFTA()->layout;
    00735       CLRBITS(st->airport.flags, layout[a->previous_pos].block | layout[a->pos].block);
    00736     }
    00737   }
    00738
    00739
    00740   if (this->type == VEH_ROAD && this->IsPrimaryVehicle()) {
    00741     RoadVehicle *v = RoadVehicle::From(this);
    00742     if (!(v->vehstatus & VS_CRASHED) && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
    00743       /* Leave the drive through roadstop, when you have not already left it. */
    00744       RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
    00745     }
    00746   }
    00747
    00748   if (this->Previous() == NULL) {
    00749     InvalidateWindowData(WC_VEHICLE_DEPOT, this->tile);
    00750   }
    00751
    00752   if (this->IsPrimaryVehicle()) {
    00753     DeleteWindowById(WC_VEHICLE_VIEW, this->index);
    00754     DeleteWindowById(WC_VEHICLE_ORDERS, this->index);
    00755     DeleteWindowById(WC_VEHICLE_REFIT, this->index);
    00756     DeleteWindowById(WC_VEHICLE_DETAILS, this->index);
    00757     DeleteWindowById(WC_VEHICLE_TIMETABLE, this->index);
    00758     SetWindowDirty(WC_COMPANY, this->owner);
    00759     OrderBackup::ClearVehicle(this);
    00760   }
    00761   InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
    00762
    00763   this->cargo.Truncate(0);
    00764   DeleteVehicleOrders(this);
    00765   DeleteDepotHighlightOfVehicle(this);
    00766
    00767   extern void StopGlobalFollowVehicle(const Vehicle *v);
    00768   StopGlobalFollowVehicle(this);
    00769
    00770   ReleaseDisastersTargetingVehicle(this->index);
    00771 }
    00772
    00773 Vehicle::~Vehicle()
    00774 {
    00775   free(this->name);
    00776
    00777   if (CleaningPool()) {
    00778     this->cargo.OnCleanPool();
    00779     return;
    00780   }
    00781
    00782   /* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles,
    00783    * it may happen that vehicle chain is deleted when visible */
    00784   if (!(this->vehstatus & VS_HIDDEN)) MarkSingleVehicleDirty(this);
    00785
    00786   Vehicle *v = this->Next();
    00787   this->SetNext(NULL);
    00788
    00789   delete v;
    00790
    00791   UpdateVehicleTileHash(this, true);
    00792   UpdateVehicleViewportHash(this, INVALID_COORD, 0);
    00793   DeleteVehicleNews(this->index, INVALID_STRING_ID);
    00794   DeleteNewGRFInspectWindow(GetGrfSpecFeature(this->type), this->index);
    00795 }
    00796
    00801 void VehicleEnteredDepotThisTick(Vehicle *v)
    00802 {
    00803   /* Vehicle should stop in the depot if it was in 'stopping' state */
    00804   _vehicles_to_autoreplace[v] = !(v->vehstatus & VS_STOPPED);
    00805
    00806   /* We ALWAYS set the stopped state. Even when the vehicle does not plan on
    00807    * stopping in the depot, so we stop it to ensure that it will not reserve
    00808    * the path out of the depot before we might autoreplace it to a different
    00809    * engine. The new engine would not own the reserved path we store that we
    00810    * stopped the vehicle, so autoreplace can start it again */
    00811   v->vehstatus |= VS_STOPPED;
    00812 }
    00813
    00819 static void RunVehicleDayProc()
    00820 {
    00821   if (_game_mode != GM_NORMAL) return;
    00822
    00823   /* Run the day_proc for every DAY_TICKS vehicle starting at _date_fract. */
    00824   for (size_t i = _date_fract; i < Vehicle::GetPoolSize(); i += DAY_TICKS) {
    00825     Vehicle *v = Vehicle::Get(i);
    00826     if (v == NULL) continue;
    00827
    00828     /* Call the 32-day callback if needed */
    00829     if ((v->day_counter & 0x1F) == 0 && v->HasEngineType()) {
    00830       uint16 callback = GetVehicleCallback(CBID_VEHICLE_32DAY_CALLBACK, 0, 0, v->engine_type, v);
    00831       if (callback != CALLBACK_FAILED) {
    00832         if (HasBit(callback, 0)) TriggerVehicle(v, VEHICLE_TRIGGER_CALLBACK_32); // Trigger vehicle trigger 10
    00833         if (HasBit(callback, 1)) v->colourmap = PAL_NONE;
    00834
    00835         if (callback & ~3) ErrorUnknownCallbackResult(v->GetGRFID(), CBID_VEHICLE_32DAY_CALLBACK, callback);
    00836       }
    00837     }
    00838
    00839     /* This is called once per day for each vehicle, but not in the first tick of the day */
    00840     v->OnNewDay();
    00841   }
    00842 }
    00843
    00844 void CallVehicleTicks()
    00845 {
    00846   _vehicles_to_autoreplace.Clear();
    00847
    00848   RunVehicleDayProc();
    00849
    00850   Station *st;
    00851   FOR_ALL_STATIONS(st) LoadUnloadStation(st);
    00852
    00853   Vehicle *v;
    00854   FOR_ALL_VEHICLES(v) {
    00855     /* Vehicle could be deleted in this tick */
    00856     if (!v->Tick()) {
    00857       assert(Vehicle::Get(vehicle_index) == NULL);
    00858       continue;
    00859     }
    00860
    00861     assert(Vehicle::Get(vehicle_index) == v);
    00862
    00863     switch (v->type) {
    00864       default: break;
    00865
    00866       case VEH_TRAIN:
    00867       case VEH_ROAD:
    00868       case VEH_AIRCRAFT:
    00869       case VEH_SHIP:
    00870         if (v->vcache.cached_cargo_age_period != 0) {
    00871           v->cargo_age_counter = min(v->cargo_age_counter, v->vcache.cached_cargo_age_period);
    00872           if (--v->cargo_age_counter == 0) {
    00873             v->cargo.AgeCargo();
    00874             v->cargo_age_counter = v->vcache.cached_cargo_age_period;
    00875           }
    00876         }
    00877
    00878         if (v->type == VEH_TRAIN && Train::From(v)->IsWagon()) continue;
    00879         if (v->type == VEH_AIRCRAFT && v->subtype != AIR_HELICOPTER) continue;
    00880         if (v->type == VEH_ROAD && !RoadVehicle::From(v)->IsFrontEngine()) continue;
    00881
    00882         v->motion_counter += v->cur_speed;
    00883         /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
    00884         if (GB(v->motion_counter, 0, 8) < v->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
    00885
    00886         /* Play an alterate running sound every 16 ticks */
    00887         if (GB(v->tick_counter, 0, 4) == 0) PlayVehicleSound(v, v->cur_speed > 0 ? VSE_RUNNING_16 : VSE_STOPPED_16);
    00888     }
    00889   }
    00890
    00891   Backup<CompanyByte> cur_company(_current_company, FILE_LINE);
    00892   for (AutoreplaceMap::iterator it = _vehicles_to_autoreplace.Begin(); it != _vehicles_to_autoreplace.End(); it++) {
    00893     v = it->first;
    00894     /* Autoreplace needs the current company set as the vehicle owner */
    00895     cur_company.Change(v->owner);
    00896
    00897     /* Start vehicle if we stopped them in VehicleEnteredDepotThisTick()
    00898      * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that
    00899      * they are already leaving the depot again before being replaced. */
    00900     if (it->second) v->vehstatus &= ~VS_STOPPED;
    00901
    00902     /* Store the position of the effect as the vehicle pointer will become invalid later */
    00903     int x = v->x_pos;
    00904     int y = v->y_pos;
    00905     int z = v->z_pos;
    00906
    00907     const Company *c = Company::Get(_current_company);
    00908     SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, (Money)c->settings.engine_renew_money));
    00909     CommandCost res = DoCommand(0, v->index, 0, DC_EXEC, CMD_AUTOREPLACE_VEHICLE);
    00910     SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, -(Money)c->settings.engine_renew_money));
    00911
    00912     if (!IsLocalCompany()) continue;
    00913
    00914     if (res.Succeeded()) {
    00915       ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
    00916       continue;
    00917     }
    00918
    00919     StringID error_message = res.GetErrorMessage();
    00920     if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message == INVALID_STRING_ID) continue;
    00921
    00922     if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT;
    00923
    00924     StringID message;
    00925     if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
    00926       message = error_message;
    00927     } else {
    00928       message = STR_NEWS_VEHICLE_AUTORENEW_FAILED;
    00929     }
    00930
    00931     SetDParam(0, v->index);
    00932     SetDParam(1, error_message);
    00933     AddVehicleNewsItem(message, NS_ADVICE, v->index);
    00934   }
    00935
    00936   cur_company.Restore();
    00937 }
    00938
    00943 static void DoDrawVehicle(const Vehicle *v)
    00944 {
    00945   SpriteID image = v->cur_image;
    00946   PaletteID pal = PAL_NONE;
    00947
    00948   if (v->vehstatus & VS_DEFPAL) pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
    00949
    00950   /* Check whether the vehicle shall be transparent due to the game state */
    00951   bool shadowed = (v->vehstatus & VS_SHADOW) != 0;
    00952
    00953   if (v->type == VEH_EFFECT) {
    00954     /* Check whether the vehicle shall be transparent/invisible due to GUI settings.
    00955      * However, transparent smoke and bubbles look weird, so always hide them. */
    00956     TransparencyOption to = EffectVehicle::From(v)->GetTransparencyOption();
    00957     if (to != TO_INVALID && (IsTransparencySet(to) || IsInvisibilitySet(to))) return;
    00958   }
    00959
    00960   AddSortableSpriteToDraw(image, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
    00961     v->x_extent, v->y_extent, v->z_extent, v->z_pos, shadowed, v->x_bb_offs, v->y_bb_offs);
    00962 }
    00963
    00968 void ViewportAddVehicles(DrawPixelInfo *dpi)
    00969 {
    00970   /* The bounding rectangle */
    00971   const int l = dpi->left;
    00972   const int r = dpi->left + dpi->width;
    00973   const int t = dpi->top;
    00974   const int b = dpi->top + dpi->height;
    00975
    00976   /* The hash area to scan */
    00977   int xl, xu, yl, yu;
    00978
    00979   if (dpi->width + (70 * ZOOM_LVL_BASE) < (1 << (7 + 6 + ZOOM_LVL_SHIFT))) {
    00980     xl = GB(l - (70 * ZOOM_LVL_BASE), 7 + ZOOM_LVL_SHIFT, 6);
    00981     xu = GB(r,                        7 + ZOOM_LVL_SHIFT, 6);
    00982   } else {
    00983     /* scan whole hash row */
    00984     xl = 0;
    00985     xu = 0x3F;
    00986   }
    00987
    00988   if (dpi->height + (70 * ZOOM_LVL_BASE) < (1 << (6 + 6 + ZOOM_LVL_SHIFT))) {
    00989     yl = GB(t - (70 * ZOOM_LVL_BASE), 6 + ZOOM_LVL_SHIFT, 6) << 6;
    00990     yu = GB(b,                        6 + ZOOM_LVL_SHIFT, 6) << 6;
    00991   } else {
    00992     /* scan whole column */
    00993     yl = 0;
    00994     yu = 0x3F << 6;
    00995   }
    00996
    00997   for (int y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
    00998     for (int x = xl;; x = (x + 1) & 0x3F) {
    00999       const Vehicle *v = _vehicle_viewport_hash[x + y]; // already masked & 0xFFF
    01000
    01001       while (v != NULL) {
    01002         if (!(v->vehstatus & VS_HIDDEN) &&
    01003             l <= v->coord.right &&
    01004             t <= v->coord.bottom &&
    01005             r >= v->coord.left &&
    01006             b >= v->coord.top) {
    01007           DoDrawVehicle(v);
    01008         }
    01009         v = v->hash_viewport_next;
    01010       }
    01011
    01012       if (x == xu) break;
    01013     }
    01014
    01015     if (y == yu) break;
    01016   }
    01017 }
    01018
    01026 Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y)
    01027 {
    01028   Vehicle *found = NULL, *v;
    01029   uint dist, best_dist = UINT_MAX;
    01030
    01031   if ((uint)(x -= vp->left) >= (uint)vp->width || (uint)(y -= vp->top) >= (uint)vp->height) return NULL;
    01032
    01033   x = ScaleByZoom(x, vp->zoom) + vp->virtual_left;
    01034   y = ScaleByZoom(y, vp->zoom) + vp->virtual_top;
    01035
    01036   FOR_ALL_VEHICLES(v) {
    01037     if ((v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0 &&
    01038         x >= v->coord.left && x <= v->coord.right &&
    01039         y >= v->coord.top && y <= v->coord.bottom) {
    01040
    01041       dist = max(
    01042         abs(((v->coord.left + v->coord.right) >> 1) - x),
    01043         abs(((v->coord.top + v->coord.bottom) >> 1) - y)
    01044       );
    01045
    01046       if (dist < best_dist) {
    01047         found = v;
    01048         best_dist = dist;
    01049       }
    01050     }
    01051   }
    01052
    01053   return found;
    01054 }
    01055
    01060 void DecreaseVehicleValue(Vehicle *v)
    01061 {
    01062   v->value -= v->value >> 8;
    01063   SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    01064 }
    01065
    01066 static const byte _breakdown_chance[64] = {
    01067     3,   3,   3,   3,   3,   3,   3,   3,
    01068     4,   4,   5,   5,   6,   6,   7,   7,
    01069     8,   8,   9,   9,  10,  10,  11,  11,
    01070    12,  13,  13,  13,  13,  14,  15,  16,
    01071    17,  19,  21,  25,  28,  31,  34,  37,
    01072    40,  44,  48,  52,  56,  60,  64,  68,
    01073    72,  80,  90, 100, 110, 120, 130, 140,
    01074   150, 170, 190, 210, 230, 250, 250, 250,
    01075 };
    01076
    01077 void CheckVehicleBreakdown(Vehicle *v)
    01078 {
    01079   int rel, rel_old;
    01080
    01081   /* decrease reliability */
    01082   v->reliability = rel = max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
    01083   if ((rel_old >> 8) != (rel >> 8)) SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    01084
    01085   if (v->breakdown_ctr != 0 || (v->vehstatus & VS_STOPPED) ||
    01086       _settings_game.difficulty.vehicle_breakdowns < 1 ||
    01087       v->cur_speed < 5 || _game_mode == GM_MENU) {
    01088     return;
    01089   }
    01090
    01091   uint32 r = Random();
    01092
    01093   /* increase chance of failure */
    01094   int chance = v->breakdown_chance + 1;
    01095   if (Chance16I(1, 25, r)) chance += 25;
    01096   v->breakdown_chance = min(255, chance);
    01097
    01098   /* calculate reliability value to use in comparison */
    01099   rel = v->reliability;
    01100   if (v->type == VEH_SHIP) rel += 0x6666;
    01101
    01102   /* reduced breakdowns? */
    01103   if (_settings_game.difficulty.vehicle_breakdowns == 1) rel += 0x6666;
    01104
    01105   /* check if to break down */
    01106   if (_breakdown_chance[(uint)min(rel, 0xffff) >> 10] <= v->breakdown_chance) {
    01107     v->breakdown_ctr    = GB(r, 16, 6) + 0x3F;
    01108     v->breakdown_delay  = GB(r, 24, 7) + 0x80;
    01109     v->breakdown_chance = 0;
    01110   }
    01111 }
    01112
    01119 bool Vehicle::HandleBreakdown()
    01120 {
    01121   /* Possible states for Vehicle::breakdown_ctr
    01122    * 0  - vehicle is running normally
    01123    * 1  - vehicle is currently broken down
    01124    * 2  - vehicle is going to break down now
    01125    * >2 - vehicle is counting down to the actual breakdown event */
    01126   switch (this->breakdown_ctr) {
    01127     case 0:
    01128       return false;
    01129
    01130     case 2:
    01131       this->breakdown_ctr = 1;
    01132
    01133       if (this->breakdowns_since_last_service != 255) {
    01134         this->breakdowns_since_last_service++;
    01135       }
    01136
    01137       if (this->type == VEH_AIRCRAFT) {
    01138         /* Aircraft just need this flag, the rest is handled elsewhere */
    01139         this->vehstatus |= VS_AIRCRAFT_BROKEN;
    01140       } else {
    01141         this->cur_speed = 0;
    01142
    01143         if (!PlayVehicleSound(this, VSE_BREAKDOWN)) {
    01144           SndPlayVehicleFx((_settings_game.game_creation.landscape != LT_TOYLAND) ?
    01145             (this->type == VEH_TRAIN ? SND_10_TRAIN_BREAKDOWN : SND_0F_VEHICLE_BREAKDOWN) :
    01146             (this->type == VEH_TRAIN ? SND_3A_COMEDY_BREAKDOWN_2 : SND_35_COMEDY_BREAKDOWN), this);
    01147         }
    01148
    01149         if (!(this->vehstatus & VS_HIDDEN)) {
    01150           EffectVehicle *u = CreateEffectVehicleRel(this, 4, 4, 5, EV_BREAKDOWN_SMOKE);
    01151           if (u != NULL) u->animation_state = this->breakdown_delay * 2;
    01152         }
    01153       }
    01154
    01155       this->MarkDirty(); // Update graphics after speed is zeroed
    01156       SetWindowDirty(WC_VEHICLE_VIEW, this->index);
    01157       SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
    01158
    01159       /* FALL THROUGH */
    01160     case 1:
    01161       /* Aircraft breakdowns end only when arriving at the airport */
    01162       if (this->type == VEH_AIRCRAFT) return false;
    01163
    01164       /* For trains this function is called twice per tick, so decrease v->breakdown_delay at half the rate */
    01165       if ((this->tick_counter & (this->type == VEH_TRAIN ? 3 : 1)) == 0) {
    01166         if (--this->breakdown_delay == 0) {
    01167           this->breakdown_ctr = 0;
    01168           this->MarkDirty();
    01169           SetWindowDirty(WC_VEHICLE_VIEW, this->index);
    01170         }
    01171       }
    01172       return true;
    01173
    01174     default:
    01175       if (!this->current_order.IsType(OT_LOADING)) this->breakdown_ctr--;
    01176       return false;
    01177   }
    01178 }
    01179
    01184 void AgeVehicle(Vehicle *v)
    01185 {
    01186   if (v->age < MAX_DAY) {
    01187     v->age++;
    01188     if (v->IsPrimaryVehicle() && v->age == VEHICLE_PROFIT_MIN_AGE + 1) GroupStatistics::VehicleReachedProfitAge(v);
    01189   }
    01190
    01191   if (!v->IsPrimaryVehicle() && (v->type != VEH_TRAIN || !Train::From(v)->IsEngine())) return;
    01192
    01193   int age = v->age - v->max_age;
    01194   if (age == DAYS_IN_LEAP_YEAR * 0 || age == DAYS_IN_LEAP_YEAR * 1 ||
    01195       age == DAYS_IN_LEAP_YEAR * 2 || age == DAYS_IN_LEAP_YEAR * 3 || age == DAYS_IN_LEAP_YEAR * 4) {
    01196     v->reliability_spd_dec <<= 1;
    01197   }
    01198
    01199   SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    01200
    01201   /* Don't warn about non-primary or not ours vehicles or vehicles that are crashed */
    01202   if (v->Previous() != NULL || v->owner != _local_company || (v->vehstatus & VS_CRASHED) != 0) return;
    01203
    01204   /* Don't warn if a renew is active */
    01205   if (Company::Get(v->owner)->settings.engine_renew && v->GetEngine()->company_avail != 0) return;
    01206
    01207   StringID str;
    01208   if (age == -DAYS_IN_LEAP_YEAR) {
    01209     str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
    01210   } else if (age == 0) {
    01211     str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
    01212   } else if (age > 0 && (age % DAYS_IN_LEAP_YEAR) == 0) {
    01213     str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
    01214   } else {
    01215     return;
    01216   }
    01217
    01218   SetDParam(0, v->index);
    01219   AddVehicleNewsItem(str, NS_ADVICE, v->index);
    01220 }
    01221
    01228 uint8 CalcPercentVehicleFilled(const Vehicle *v, StringID *colour)
    01229 {
    01230   int count = 0;
    01231   int max = 0;
    01232   int cars = 0;
    01233   int unloading = 0;
    01234   bool loading = false;
    01235
    01236   const Vehicle *u = v;
    01237   /* The station may be NULL when the (colour) string does not need to be set. */
    01238   const Station *st = Station::GetIfValid(v->last_station_visited);
    01239   assert(colour == NULL || st != NULL);
    01240
    01241   /* Count up max and used */
    01242   for (; v != NULL; v = v->Next()) {
    01243     count += v->cargo.Count();
    01244     max += v->cargo_cap;
    01245     if (v->cargo_cap != 0 && colour != NULL) {
    01246       unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0;
    01247       loading |= !(u->current_order.GetLoadType() & OLFB_NO_LOAD) && st->goods[v->cargo_type].days_since_pickup != 255;
    01248       cars++;
    01249     }
    01250   }
    01251
    01252   if (colour != NULL) {
    01253     if (unloading == 0 && loading) {
    01254       *colour = STR_PERCENT_UP;
    01255     } else if (cars == unloading || !loading) {
    01256       *colour = STR_PERCENT_DOWN;
    01257     } else {
    01258       *colour = STR_PERCENT_UP_DOWN;
    01259     }
    01260   }
    01261
    01262   /* Train without capacity */
    01263   if (max == 0) return 100;
    01264
    01265   /* Return the percentage */
    01266   return (count * 100) / max;
    01267 }
    01268
    01273 void VehicleEnterDepot(Vehicle *v)
    01274 {
    01275   /* Always work with the front of the vehicle */
    01276   assert(v == v->First());
    01277
    01278   switch (v->type) {
    01279     case VEH_TRAIN: {
    01280       Train *t = Train::From(v);
    01281       SetWindowClassesDirty(WC_TRAINS_LIST);
    01282       /* Clear path reservation */
    01283       SetDepotReservation(t->tile, false);
    01284       if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(t->tile);
    01285
    01286       UpdateSignalsOnSegment(t->tile, INVALID_DIAGDIR, t->owner);
    01287       t->wait_counter = 0;
    01288       t->force_proceed = TFP_NONE;
    01289       ClrBit(t->flags, VRF_TOGGLE_REVERSE);
    01290       t->ConsistChanged(true);
    01291       break;
    01292     }
    01293
    01294     case VEH_ROAD:
    01295       SetWindowClassesDirty(WC_ROADVEH_LIST);
    01296       break;
    01297
    01298     case VEH_SHIP: {
    01299       SetWindowClassesDirty(WC_SHIPS_LIST);
    01300       Ship *ship = Ship::From(v);
    01301       ship->state = TRACK_BIT_DEPOT;
    01302       ship->UpdateCache();
    01303       ship->UpdateViewport(true, true);
    01304       SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
    01305       break;
    01306     }
    01307
    01308     case VEH_AIRCRAFT:
    01309       SetWindowClassesDirty(WC_AIRCRAFT_LIST);
    01310       HandleAircraftEnterHangar(Aircraft::From(v));
    01311       break;
    01312     default: NOT_REACHED();
    01313   }
    01314   SetWindowDirty(WC_VEHICLE_VIEW, v->index);
    01315
    01316   if (v->type != VEH_TRAIN) {
    01317     /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
    01318      * 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 */
    01319     InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
    01320   }
    01321   SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
    01322
    01323   v->vehstatus |= VS_HIDDEN;
    01324   v->cur_speed = 0;
    01325
    01326   VehicleServiceInDepot(v);
    01327
    01328   TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
    01329
    01330   if (v->current_order.IsType(OT_GOTO_DEPOT)) {
    01331     SetWindowDirty(WC_VEHICLE_VIEW, v->index);
    01332
    01333     const Order *real_order = v->GetOrder(v->cur_real_order_index);
    01334     Order t = v->current_order;
    01335     v->current_order.MakeDummy();
    01336
    01337     /* Test whether we are heading for this depot. If not, do nothing.
    01338      * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
    01339     if ((t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) &&
    01340         real_order != NULL && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) &&
    01341         (v->type == VEH_AIRCRAFT ? t.GetDestination() != GetStationIndex(v->tile) : v->dest_tile != v->tile)) {
    01342       /* We are heading for another depot, keep driving. */
    01343       return;
    01344     }
    01345
    01346     if (t.IsRefit()) {
    01347       Backup<CompanyByte> cur_company(_current_company, v->owner, FILE_LINE);
    01348       CommandCost cost = DoCommand(v->tile, v->index, t.GetRefitCargo() | t.GetRefitSubtype() << 8, DC_EXEC, GetCmdRefitVeh(v));
    01349       cur_company.Restore();
    01350
    01351       if (cost.Failed()) {
    01352         _vehicles_to_autoreplace[v] = false;
    01353         if (v->owner == _local_company) {
    01354           /* Notify the user that we stopped the vehicle */
    01355           SetDParam(0, v->index);
    01356           AddVehicleNewsItem(STR_NEWS_ORDER_REFIT_FAILED, NS_ADVICE, v->index);
    01357         }
    01358       } else if (cost.GetCost() != 0) {
    01359         v->profit_this_year -= cost.GetCost() << 8;
    01360         if (v->owner == _local_company) {
    01361           ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
    01362         }
    01363       }
    01364     }
    01365
    01366     if (t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
    01367       /* Part of orders */
    01368       v->DeleteUnreachedImplicitOrders();
    01369       UpdateVehicleTimetable(v, true);
    01370       v->IncrementImplicitOrderIndex();
    01371     }
    01372     if (t.GetDepotActionType() & ODATFB_HALT) {
    01373       /* Vehicles are always stopped on entering depots. Do not restart this one. */
    01374       _vehicles_to_autoreplace[v] = false;
    01375       if (v->owner == _local_company) {
    01376         SetDParam(0, v->index);
    01377         AddVehicleNewsItem(STR_NEWS_TRAIN_IS_WAITING + v->type, NS_ADVICE, v->index);
    01378       }
    01379       AI::NewEvent(v->owner, new ScriptEventVehicleWaitingInDepot(v->index));
    01380     }
    01381   }
    01382 }
    01383
    01384
    01390 void VehicleUpdatePosition(Vehicle *v)
    01391 {
    01392   UpdateVehicleTileHash(v, false);
    01393 }
    01394
    01401 void VehicleUpdateViewport(Vehicle *v, bool dirty)
    01402 {
    01403   int img = v->cur_image;
    01404   Point pt = RemapCoords(v->x_pos + v->x_offs, v->y_pos + v->y_offs, v->z_pos);
    01405   const Sprite *spr = GetSprite(img, ST_NORMAL);
    01406
    01407   pt.x += spr->x_offs;
    01408   pt.y += spr->y_offs;
    01409
    01410   UpdateVehicleViewportHash(v, pt.x, pt.y);
    01411
    01412   Rect old_coord = v->coord;
    01413   v->coord.left   = pt.x;
    01414   v->coord.top    = pt.y;
    01415   v->coord.right  = pt.x + spr->width + 2 * ZOOM_LVL_BASE;
    01416   v->coord.bottom = pt.y + spr->height + 2 * ZOOM_LVL_BASE;
    01417
    01418   if (dirty) {
    01419     MarkAllViewportsDirty(
    01420       min(old_coord.left,   v->coord.left),
    01421       min(old_coord.top,    v->coord.top),
    01422       max(old_coord.right,  v->coord.right) + 1 * ZOOM_LVL_BASE,
    01423       max(old_coord.bottom, v->coord.bottom) + 1 * ZOOM_LVL_BASE
    01424     );
    01425   }
    01426 }
    01427
    01432 void VehicleUpdatePositionAndViewport(Vehicle *v)
    01433 {
    01434   VehicleUpdatePosition(v);
    01435   VehicleUpdateViewport(v, true);
    01436 }
    01437
    01442 void MarkSingleVehicleDirty(const Vehicle *v)
    01443 {
    01444   MarkAllViewportsDirty(v->coord.left, v->coord.top, v->coord.right + 1 * ZOOM_LVL_BASE, v->coord.bottom + 1 * ZOOM_LVL_BASE);
    01445 }
    01446
    01452 GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
    01453 {
    01454   static const int8 _delta_coord[16] = {
    01455     -1,-1,-1, 0, 1, 1, 1, 0, /* x */
    01456     -1, 0, 1, 1, 1, 0,-1,-1, /* y */
    01457   };
    01458
    01459   int x = v->x_pos + _delta_coord[v->direction];
    01460   int y = v->y_pos + _delta_coord[v->direction + 8];
    01461
    01462   GetNewVehiclePosResult gp;
    01463   gp.x = x;
    01464   gp.y = y;
    01465   gp.old_tile = v->tile;
    01466   gp.new_tile = TileVirtXY(x, y);
    01467   return gp;
    01468 }
    01469
    01470 static const Direction _new_direction_table[] = {
    01471   DIR_N,  DIR_NW, DIR_W,
    01472   DIR_NE, DIR_SE, DIR_SW,
    01473   DIR_E,  DIR_SE, DIR_S
    01474 };
    01475
    01476 Direction GetDirectionTowards(const Vehicle *v, int x, int y)
    01477 {
    01478   int i = 0;
    01479
    01480   if (y >= v->y_pos) {
    01481     if (y != v->y_pos) i += 3;
    01482     i += 3;
    01483   }
    01484
    01485   if (x >= v->x_pos) {
    01486     if (x != v->x_pos) i++;
    01487     i++;
    01488   }
    01489
    01490   Direction dir = v->direction;
    01491
    01492   DirDiff dirdiff = DirDifference(_new_direction_table[i], dir);
    01493   if (dirdiff == DIRDIFF_SAME) return dir;
    01494   return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
    01495 }
    01496
    01506 VehicleEnterTileStatus VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
    01507 {
    01508   return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
    01509 }
    01510
    01518 FreeUnitIDGenerator::FreeUnitIDGenerator(VehicleType type, CompanyID owner) : cache(NULL), maxid(0), curid(0)
    01519 {
    01520   /* Find maximum */
    01521   const Vehicle *v;
    01522   FOR_ALL_VEHICLES(v) {
    01523     if (v->type == type && v->owner == owner) {
    01524       this->maxid = max<UnitID>(this->maxid, v->unitnumber);
    01525     }
    01526   }
    01527
    01528   if (this->maxid == 0) return;
    01529
    01530   /* Reserving 'maxid + 2' because we need:
    01531    * - space for the last item (with v->unitnumber == maxid)
    01532    * - one free slot working as loop terminator in FreeUnitIDGenerator::NextID() */
    01533   this->cache = CallocT<bool>(this->maxid + 2);
    01534
    01535   /* Fill the cache */
    01536   FOR_ALL_VEHICLES(v) {
    01537     if (v->type == type && v->owner == owner) {
    01538       this->cache[v->unitnumber] = true;
    01539     }
    01540   }
    01541 }
    01542
    01544 UnitID FreeUnitIDGenerator::NextID()
    01545 {
    01546   if (this->maxid <= this->curid) return ++this->curid;
    01547
    01548   while (this->cache[++this->curid]) { } // it will stop, we reserved more space than needed
    01549
    01550   return this->curid;
    01551 }
    01552
    01558 UnitID GetFreeUnitNumber(VehicleType type)
    01559 {
    01560   /* Check whether it is allowed to build another vehicle. */
    01561   uint max_veh;
    01562   switch (type) {
    01563     case VEH_TRAIN:    max_veh = _settings_game.vehicle.max_trains;   break;
    01564     case VEH_ROAD:     max_veh = _settings_game.vehicle.max_roadveh;  break;
    01565     case VEH_SHIP:     max_veh = _settings_game.vehicle.max_ships;    break;
    01566     case VEH_AIRCRAFT: max_veh = _settings_game.vehicle.max_aircraft; break;
    01567     default: NOT_REACHED();
    01568   }
    01569
    01570   const Company *c = Company::Get(_current_company);
    01571   if (c->group_all[type].num_vehicle >= max_veh) return UINT16_MAX; // Currently already at the limit, no room to make a new one.
    01572
    01573   FreeUnitIDGenerator gen(type, _current_company);
    01574
    01575   return gen.NextID();
    01576 }
    01577
    01578
    01587 bool CanBuildVehicleInfrastructure(VehicleType type)
    01588 {
    01589   assert(IsCompanyBuildableVehicleType(type));
    01590
    01591   if (!Company::IsValidID(_local_company)) return false;
    01592   if (!_settings_client.gui.disable_unsuitable_building) return true;
    01593
    01594   UnitID max;
    01595   switch (type) {
    01596     case VEH_TRAIN:    max = _settings_game.vehicle.max_trains; break;
    01597     case VEH_ROAD:     max = _settings_game.vehicle.max_roadveh; break;
    01598     case VEH_SHIP:     max = _settings_game.vehicle.max_ships; break;
    01599     case VEH_AIRCRAFT: max = _settings_game.vehicle.max_aircraft; break;
    01600     default: NOT_REACHED();
    01601   }
    01602
    01603   /* We can build vehicle infrastructure when we may build the vehicle type */
    01604   if (max > 0) {
    01605     /* Can we actually build the vehicle type? */
    01606     const Engine *e;
    01607     FOR_ALL_ENGINES_OF_TYPE(e, type) {
    01608       if (HasBit(e->company_avail, _local_company)) return true;
    01609     }
    01610     return false;
    01611   }
    01612
    01613   /* We should be able to build infrastructure when we have the actual vehicle type */
    01614   const Vehicle *v;
    01615   FOR_ALL_VEHICLES(v) {
    01616     if (v->owner == _local_company && v->type == type) return true;
    01617   }
    01618
    01619   return false;
    01620 }
    01621
    01622
    01630 LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
    01631 {
    01632   CargoID cargo_type = v == NULL ? (CargoID)CT_INVALID : v->cargo_type;
    01633   const Engine *e = Engine::Get(engine_type);
    01634   switch (e->type) {
    01635     default: NOT_REACHED();
    01636     case VEH_TRAIN:
    01637       if (v != NULL && parent_engine_type != INVALID_ENGINE && (UsesWagonOverride(v) || (v->IsArticulatedPart() && e->u.rail.railveh_type != RAILVEH_WAGON))) {
    01638         /* Wagonoverrides use the colour scheme of the front engine.
    01639          * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */
    01640         engine_type = parent_engine_type;
    01641         e = Engine::Get(engine_type);
    01642         /* Note: Luckily cargo_type is not needed for engines */
    01643       }
    01644
    01645       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01646       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01647       if (e->u.rail.railveh_type == RAILVEH_WAGON) {
    01648         if (!CargoSpec::Get(cargo_type)->is_freight) {
    01649           if (parent_engine_type == INVALID_ENGINE) {
    01650             return LS_PASSENGER_WAGON_STEAM;
    01651           } else {
    01652             switch (RailVehInfo(parent_engine_type)->engclass) {
    01653               default: NOT_REACHED();
    01654               case EC_STEAM:    return LS_PASSENGER_WAGON_STEAM;
    01655               case EC_DIESEL:   return LS_PASSENGER_WAGON_DIESEL;
    01656               case EC_ELECTRIC: return LS_PASSENGER_WAGON_ELECTRIC;
    01657               case EC_MONORAIL: return LS_PASSENGER_WAGON_MONORAIL;
    01658               case EC_MAGLEV:   return LS_PASSENGER_WAGON_MAGLEV;
    01659             }
    01660           }
    01661         } else {
    01662           return LS_FREIGHT_WAGON;
    01663         }
    01664       } else {
    01665         bool is_mu = HasBit(e->info.misc_flags, EF_RAIL_IS_MU);
    01666
    01667         switch (e->u.rail.engclass) {
    01668           default: NOT_REACHED();
    01669           case EC_STEAM:    return LS_STEAM;
    01670           case EC_DIESEL:   return is_mu ? LS_DMU : LS_DIESEL;
    01671           case EC_ELECTRIC: return is_mu ? LS_EMU : LS_ELECTRIC;
    01672           case EC_MONORAIL: return LS_MONORAIL;
    01673           case EC_MAGLEV:   return LS_MAGLEV;
    01674         }
    01675       }
    01676
    01677     case VEH_ROAD:
    01678       /* Always use the livery of the front */
    01679       if (v != NULL && parent_engine_type != INVALID_ENGINE) {
    01680         engine_type = parent_engine_type;
    01681         e = Engine::Get(engine_type);
    01682         cargo_type = v->First()->cargo_type;
    01683       }
    01684       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01685       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01686
    01687       /* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */
    01688       if (HasBit(e->info.misc_flags, EF_ROAD_TRAM)) {
    01689         /* Tram */
    01690         return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
    01691       } else {
    01692         /* Bus or truck */
    01693         return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_BUS : LS_TRUCK;
    01694       }
    01695
    01696     case VEH_SHIP:
    01697       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01698       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01699       return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
    01700
    01701     case VEH_AIRCRAFT:
    01702       switch (e->u.air.subtype) {
    01703         case AIR_HELI: return LS_HELICOPTER;
    01704         case AIR_CTOL: return LS_SMALL_PLANE;
    01705         case AIR_CTOL | AIR_FAST: return LS_LARGE_PLANE;
    01706         default: NOT_REACHED();
    01707       }
    01708   }
    01709 }
    01710
    01720 const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, byte livery_setting)
    01721 {
    01722   const Company *c = Company::Get(company);
    01723   LiveryScheme scheme = LS_DEFAULT;
    01724
    01725   /* The default livery is always available for use, but its in_use flag determines
    01726    * whether any _other_ liveries are in use. */
    01727   if (c->livery[LS_DEFAULT].in_use && (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company))) {
    01728     /* Determine the livery scheme to use */
    01729     scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
    01730
    01731     /* Switch back to the default scheme if the resolved scheme is not in use */
    01732     if (!c->livery[scheme].in_use) scheme = LS_DEFAULT;
    01733   }
    01734
    01735   return &c->livery[scheme];
    01736 }
    01737
    01738
    01739 static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
    01740 {
    01741   PaletteID map = (v != NULL) ? v->colourmap : PAL_NONE;
    01742
    01743   /* Return cached value if any */
    01744   if (map != PAL_NONE) return map;
    01745
    01746   const Engine *e = Engine::Get(engine_type);
    01747
    01748   /* Check if we should use the colour map callback */
    01749   if (HasBit(e->info.callback_mask, CBM_VEHICLE_COLOUR_REMAP)) {
    01750     uint16 callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
    01751     /* Failure means "use the default two-colour" */
    01752     if (callback != CALLBACK_FAILED) {
    01753       assert_compile(PAL_NONE == 0); // Returning 0x4000 (resp. 0xC000) conincidences with default value (PAL_NONE)
    01754       map = GB(callback, 0, 14);
    01755       /* If bit 14 is set, then the company colours are applied to the
    01756        * map else it's returned as-is. */
    01757       if (!HasBit(callback, 14)) {
    01758         /* Update cache */
    01759         if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
    01760         return map;
    01761       }
    01762     }
    01763   }
    01764
    01765   bool twocc = HasBit(e->info.misc_flags, EF_USES_2CC);
    01766
    01767   if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
    01768
    01769   /* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
    01770   if (!Company::IsValidID(company)) return map;
    01771
    01772   const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries);
    01773
    01774   map += livery->colour1;
    01775   if (twocc) map += livery->colour2 * 16;
    01776
    01777   /* Update cache */
    01778   if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
    01779   return map;
    01780 }
    01781
    01788 PaletteID GetEnginePalette(EngineID engine_type, CompanyID company)
    01789 {
    01790   return GetEngineColourMap(engine_type, company, INVALID_ENGINE, NULL);
    01791 }
    01792
    01798 PaletteID GetVehiclePalette(const Vehicle *v)
    01799 {
    01800   if (v->IsGroundVehicle()) {
    01801     return GetEngineColourMap(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v);
    01802   }
    01803
    01804   return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
    01805 }
    01806
    01810 void Vehicle::DeleteUnreachedImplicitOrders()
    01811 {
    01812   if (this->IsGroundVehicle()) {
    01813     uint16 &gv_flags = this->GetGroundVehicleFlags();
    01814     if (HasBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS)) {
    01815       /* Do not delete orders, only skip them */
    01816       ClrBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
    01817       this->cur_implicit_order_index = this->cur_real_order_index;
    01818       InvalidateVehicleOrder(this, 0);
    01819       return;
    01820     }
    01821   }
    01822
    01823   const Order *order = this->GetOrder(this->cur_implicit_order_index);
    01824   while (order != NULL) {
    01825     if (this->cur_implicit_order_index == this->cur_real_order_index) break;
    01826
    01827     if (order->IsType(OT_IMPLICIT)) {
    01828       /* Delete order effectively deletes order, so get the next before deleting it. */
    01829       order = order->next;
    01830       DeleteOrder(this, this->cur_implicit_order_index);
    01831     } else {
    01832       /* Skip non-implicit orders, e.g. service-orders */
    01833       order = order->next;
    01834       this->cur_implicit_order_index++;
    01835     }
    01836
    01837     /* Wrap around */
    01838     if (order == NULL) {
    01839       order = this->GetOrder(0);
    01840       this->cur_implicit_order_index = 0;
    01841     }
    01842   }
    01843 }
    01844
    01849 void Vehicle::BeginLoading()
    01850 {
    01851   assert(IsTileType(this->tile, MP_STATION) || this->type == VEH_SHIP);
    01852
    01853   if (this->current_order.IsType(OT_GOTO_STATION) &&
    01854       this->current_order.GetDestination() == this->last_station_visited) {
    01855     this->DeleteUnreachedImplicitOrders();
    01856
    01857     /* Now both order indices point to the destination station, and we can start loading */
    01858     this->current_order.MakeLoading(true);
    01859     UpdateVehicleTimetable(this, true);
    01860
    01861     /* Furthermore add the Non Stop flag to mark that this station
    01862      * is the actual destination of the vehicle, which is (for example)
    01863      * necessary to be known for HandleTrainLoading to determine
    01864      * whether the train is lost or not; not marking a train lost
    01865      * that arrives at random stations is bad. */
    01866     this->current_order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
    01867
    01868   } else {
    01869     /* We weren't scheduled to stop here. Insert an implicit order
    01870      * to show that we are stopping here, but only do that if the order
    01871      * list isn't empty.
    01872      * While only groundvehicles have implicit orders, e.g. aircraft might still enter
    01873      * the 'wrong' terminal when skipping orders etc. */
    01874     Order *in_list = this->GetOrder(this->cur_implicit_order_index);
    01875     if (this->IsGroundVehicle() && in_list != NULL &&
    01876         (!in_list->IsType(OT_IMPLICIT) ||
    01877         in_list->GetDestination() != this->last_station_visited)) {
    01878       bool suppress_implicit_orders = HasBit(this->GetGroundVehicleFlags(), GVF_SUPPRESS_IMPLICIT_ORDERS);
    01879       /* Do not create consecutive duplicates of implicit orders */
    01880       Order *prev_order = this->cur_implicit_order_index > 0 ? this->GetOrder(this->cur_implicit_order_index - 1) : (this->GetNumOrders() > 1 ? this->GetLastOrder() : NULL);
    01881       if (prev_order == NULL ||
    01882           (!prev_order->IsType(OT_IMPLICIT) && !prev_order->IsType(OT_GOTO_STATION)) ||
    01883           prev_order->GetDestination() != this->last_station_visited) {
    01884
    01885         /* Prefer deleting implicit orders instead of inserting new ones,
    01886          * so test whether the right order follows later */
    01887         int target_index = this->cur_implicit_order_index;
    01888         bool found = false;
    01889         while (target_index != this->cur_real_order_index) {
    01890           const Order *order = this->GetOrder(target_index);
    01891           if (order->IsType(OT_IMPLICIT) && order->GetDestination() == this->last_station_visited) {
    01892             found = true;
    01893             break;
    01894           }
    01895           target_index++;
    01896           if (target_index >= this->orders.list->GetNumOrders()) target_index = 0;
    01897           assert(target_index != this->cur_implicit_order_index); // infinite loop?
    01898         }
    01899
    01900         if (found) {
    01901           if (suppress_implicit_orders) {
    01902             /* Skip to the found order */
    01903             this->cur_implicit_order_index = target_index;
    01904             InvalidateVehicleOrder(this, 0);
    01905           } else {
    01906             /* Delete all implicit orders up to the station we just reached */
    01907             const Order *order = this->GetOrder(this->cur_implicit_order_index);
    01908             while (!order->IsType(OT_IMPLICIT) || order->GetDestination() != this->last_station_visited) {
    01909               if (order->IsType(OT_IMPLICIT)) {
    01910                 /* Delete order effectively deletes order, so get the next before deleting it. */
    01911                 order = order->next;
    01912                 DeleteOrder(this, this->cur_implicit_order_index);
    01913               } else {
    01914                 /* Skip non-implicit orders, e.g. service-orders */
    01915                 order = order->next;
    01916                 this->cur_implicit_order_index++;
    01917               }
    01918
    01919               /* Wrap around */
    01920               if (order == NULL) {
    01921                 order = this->GetOrder(0);
    01922                 this->cur_implicit_order_index = 0;
    01923               }
    01924               assert(order != NULL);
    01925             }
    01926           }
    01927         } else if (!suppress_implicit_orders && this->orders.list->GetNumOrders() < MAX_VEH_ORDER_ID && Order::CanAllocateItem()) {
    01928           /* Insert new implicit order */
    01929           Order *implicit_order = new Order();
    01930           implicit_order->MakeImplicit(this->last_station_visited);
    01931           InsertOrder(this, implicit_order, this->cur_implicit_order_index);
    01932           if (this->cur_implicit_order_index > 0) --this->cur_implicit_order_index;
    01933
    01934           /* InsertOrder disabled creation of implicit orders for all vehicles with the same implicit order.
    01935            * Reenable it for this vehicle */
    01936           uint16 &gv_flags = this->GetGroundVehicleFlags();
    01937           ClrBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
    01938         }
    01939       }
    01940     }
    01941     this->current_order.MakeLoading(false);
    01942   }
    01943
    01944   Station::Get(this->last_station_visited)->loading_vehicles.push_back(this);
    01945
    01946   PrepareUnload(this);
    01947
    01948   SetWindowDirty(GetWindowClassForVehicleType(this->type), this->owner);
    01949   SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
    01950   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
    01951   SetWindowDirty(WC_STATION_VIEW, this->last_station_visited);
    01952
    01953   Station::Get(this->last_station_visited)->MarkTilesDirty(true);
    01954   this->cur_speed = 0;
    01955   this->MarkDirty();
    01956 }
    01957
    01962 void Vehicle::LeaveStation()
    01963 {
    01964   assert(this->current_order.IsType(OT_LOADING));
    01965
    01966   delete this->cargo_payment;
    01967
    01968   /* Only update the timetable if the vehicle was supposed to stop here. */
    01969   if (this->current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE) UpdateVehicleTimetable(this, false);
    01970
    01971   this->current_order.MakeLeaveStation();
    01972   Station *st = Station::Get(this->last_station_visited);
    01973   st->loading_vehicles.remove(this);
    01974
    01975   HideFillingPercent(&this->fill_percent_te_id);
    01976
    01977   if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) {
    01978     /* Trigger station animation (trains only) */
    01979     if (IsTileType(this->tile, MP_STATION)) TriggerStationAnimation(st, this->tile, SAT_TRAIN_DEPARTS);
    01980
    01981     SetBit(Train::From(this)->flags, VRF_LEAVING_STATION);
    01982   }
    01983 }
    01984
    01985
    01991 void Vehicle::HandleLoading(bool mode)
    01992 {
    01993   switch (this->current_order.GetType()) {
    01994     case OT_LOADING: {
    01995       uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0);
    01996
    01997       /* Not the first call for this tick, or still loading */
    01998       if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || this->current_order_time < wait_time) return;
    01999
    02000       this->PlayLeaveStationSound();
    02001
    02002       this->LeaveStation();
    02003
    02004       /* Only advance to next order if we just loaded at the current one */
    02005       const Order *order = this->GetOrder(this->cur_implicit_order_index);
    02006       if (order == NULL ||
    02007           (!order->IsType(OT_IMPLICIT) && !order->IsType(OT_GOTO_STATION)) ||
    02008           order->GetDestination() != this->last_station_visited) {
    02009         return;
    02010       }
    02011       break;
    02012     }
    02013
    02014     case OT_DUMMY: break;
    02015
    02016     default: return;
    02017   }
    02018
    02019   this->IncrementImplicitOrderIndex();
    02020 }
    02021
    02028 CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command)
    02029 {
    02030   CommandCost ret = CheckOwnership(this->owner);
    02031   if (ret.Failed()) return ret;
    02032
    02033   if (this->vehstatus & VS_CRASHED) return CMD_ERROR;
    02034   if (this->IsStoppedInDepot()) return CMD_ERROR;
    02035
    02036   if (this->current_order.IsType(OT_GOTO_DEPOT)) {
    02037     bool halt_in_depot = (this->current_order.GetDepotActionType() & ODATFB_HALT) != 0;
    02038     if (!!(command & DEPOT_SERVICE) == halt_in_depot) {
    02039       /* We called with a different DEPOT_SERVICE setting.
    02040        * Now we change the setting to apply the new one and let the vehicle head for the same depot.
    02041        * Note: the if is (true for requesting service == true for ordered to stop in depot)          */
    02042       if (flags & DC_EXEC) {
    02043         this->current_order.SetDepotOrderType(ODTF_MANUAL);
    02044         this->current_order.SetDepotActionType(halt_in_depot ? ODATF_SERVICE_ONLY : ODATFB_HALT);
    02045         SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
    02046       }
    02047       return CommandCost();
    02048     }
    02049
    02050     if (command & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
    02051     if (flags & DC_EXEC) {
    02052       /* If the orders to 'goto depot' are in the orders list (forced servicing),
    02053        * then skip to the next order; effectively cancelling this forced service */
    02054       if (this->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) this->IncrementRealOrderIndex();
    02055
    02056       if (this->IsGroundVehicle()) {
    02057         uint16 &gv_flags = this->GetGroundVehicleFlags();
    02058         SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
    02059       }
    02060
    02061       this->current_order.MakeDummy();
    02062       SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
    02063     }
    02064     return CommandCost();
    02065   }
    02066
    02067   TileIndex location;
    02068   DestinationID destination;
    02069   bool reverse;
    02070   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};
    02071   if (!this->FindClosestDepot(&location, &destination, &reverse)) return_cmd_error(no_depot[this->type]);
    02072
    02073   if (flags & DC_EXEC) {
    02074     if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
    02075
    02076     if (this->IsGroundVehicle()) {
    02077       uint16 &gv_flags = this->GetGroundVehicleFlags();
    02078       SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
    02079     }
    02080
    02081     this->dest_tile = location;
    02082     this->current_order.MakeGoToDepot(destination, ODTF_MANUAL);
    02083     if (!(command & DEPOT_SERVICE)) this->current_order.SetDepotActionType(ODATFB_HALT);
    02084     SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
    02085
    02086     /* If there is no depot in front, reverse automatically (trains only) */
    02087     if (this->type == VEH_TRAIN && reverse) DoCommand(this->tile, this->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
    02088
    02089     if (this->type == VEH_AIRCRAFT) {
    02090       Aircraft *a = Aircraft::From(this);
    02091       if (a->state == FLYING && a->targetairport != destination) {
    02092         /* The aircraft is now heading for a different hangar than the next in the orders */
    02093         extern void AircraftNextAirportPos_and_Order(Aircraft *a);
    02094         AircraftNextAirportPos_and_Order(a);
    02095       }
    02096     }
    02097   }
    02098
    02099   return CommandCost();
    02100
    02101 }
    02102
    02107 void Vehicle::UpdateVisualEffect(bool allow_power_change)
    02108 {
    02109   bool powered_before = HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
    02110   const Engine *e = this->GetEngine();
    02111
    02112   /* Evaluate properties */
    02113   byte visual_effect;
    02114   switch (e->type) {
    02115     case VEH_TRAIN: visual_effect = e->u.rail.visual_effect; break;
    02116     case VEH_ROAD:  visual_effect = e->u.road.visual_effect; break;
    02117     case VEH_SHIP:  visual_effect = e->u.ship.visual_effect; break;
    02118     default:        visual_effect = 1 << VE_DISABLE_EFFECT;  break;
    02119   }
    02120
    02121   /* Check powered wagon / visual effect callback */
    02122   if (HasBit(e->info.callback_mask, CBM_VEHICLE_VISUAL_EFFECT)) {
    02123     uint16 callback = GetVehicleCallback(CBID_VEHICLE_VISUAL_EFFECT, 0, 0, this->engine_type, this);
    02124
    02125     if (callback != CALLBACK_FAILED) {
    02126       if (callback >= 0x100 && e->GetGRF()->grf_version >= 8) ErrorUnknownCallbackResult(e->GetGRFID(), CBID_VEHICLE_VISUAL_EFFECT, callback);
    02127
    02128       callback = GB(callback, 0, 8);
    02129       /* Avoid accidentally setting 'visual_effect' to the default value
    02130        * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
    02131       if (callback == VE_DEFAULT) {
    02132         assert(HasBit(callback, VE_DISABLE_EFFECT));
    02133         SB(callback, VE_TYPE_START, VE_TYPE_COUNT, 0);
    02134       }
    02135       visual_effect = callback;
    02136     }
    02137   }
    02138
    02139   /* Apply default values */
    02140   if (visual_effect == VE_DEFAULT ||
    02141       (!HasBit(visual_effect, VE_DISABLE_EFFECT) && GB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT) == VE_TYPE_DEFAULT)) {
    02142     /* Only train engines have default effects.
    02143      * Note: This is independent of whether the engine is a front engine or articulated part or whatever. */
    02144     if (e->type != VEH_TRAIN || e->u.rail.railveh_type == RAILVEH_WAGON || !IsInsideMM(e->u.rail.engclass, EC_STEAM, EC_MONORAIL)) {
    02145       if (visual_effect == VE_DEFAULT) {
    02146         visual_effect = 1 << VE_DISABLE_EFFECT;
    02147       } else {
    02148         SetBit(visual_effect, VE_DISABLE_EFFECT);
    02149       }
    02150     } else {
    02151       if (visual_effect == VE_DEFAULT) {
    02152         /* Also set the offset */
    02153         visual_effect = (VE_OFFSET_CENTRE - (e->u.rail.engclass == EC_STEAM ? 4 : 0)) << VE_OFFSET_START;
    02154       }
    02155       SB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT, e->u.rail.engclass - EC_STEAM + VE_TYPE_STEAM);
    02156     }
    02157   }
    02158
    02159   this->vcache.cached_vis_effect = visual_effect;
    02160
    02161   if (!allow_power_change && powered_before != HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
    02162     ToggleBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
    02163     ShowNewGrfVehicleError(this->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_POWERED_WAGON, GBUG_VEH_POWERED_WAGON, false);
    02164   }
    02165 }
    02166
    02167 static const int8 _vehicle_smoke_pos[8] = {
    02168   1, 1, 1, 0, -1, -1, -1, 0
    02169 };
    02170
    02175 void Vehicle::ShowVisualEffect() const
    02176 {
    02177   assert(this->IsPrimaryVehicle());
    02178   bool sound = false;
    02179
    02180   /* Do not show any smoke when:
    02181    * - vehicle smoke is disabled by the player
    02182    * - the vehicle is slowing down or stopped (by the player)
    02183    * - the vehicle is moving very slowly
    02184    */
    02185   if (_settings_game.vehicle.smoke_amount == 0 ||
    02186       this->vehstatus & (VS_TRAIN_SLOWING | VS_STOPPED) ||
    02187       this->cur_speed < 2) {
    02188     return;
    02189   }
    02190   if (this->type == VEH_TRAIN) {
    02191     const Train *t = Train::From(this);
    02192     /* For trains, do not show any smoke when:
    02193      * - the train is reversing
    02194      * - is entering a station with an order to stop there and its speed is equal to maximum station entering speed
    02195      */
    02196     if (HasBit(t->flags, VRF_REVERSING) ||
    02197         (IsRailStationTile(t->tile) && t->IsFrontEngine() && t->current_order.ShouldStopAtStation(t, GetStationIndex(t->tile)) &&
    02198         t->cur_speed >= t->Train::GetCurrentMaxSpeed())) {
    02199       return;
    02200     }
    02201   }
    02202
    02203   const Vehicle *v = this;
    02204
    02205   do {
    02206     int effect_offset = GB(v->vcache.cached_vis_effect, VE_OFFSET_START, VE_OFFSET_COUNT) - VE_OFFSET_CENTRE;
    02207     byte effect_type = GB(v->vcache.cached_vis_effect, VE_TYPE_START, VE_TYPE_COUNT);
    02208     bool disable_effect = HasBit(v->vcache.cached_vis_effect, VE_DISABLE_EFFECT);
    02209
    02210     /* Show no smoke when:
    02211      * - Smoke has been disabled for this vehicle
    02212      * - The vehicle is not visible
    02213      * - The vehicle is under a bridge
    02214      * - The vehicle is on a depot tile
    02215      * - The vehicle is on a tunnel tile
    02216      * - The vehicle is a train engine that is currently unpowered */
    02217     if (disable_effect ||
    02218         v->vehstatus & VS_HIDDEN ||
    02219         (MayHaveBridgeAbove(v->tile) && IsBridgeAbove(v->tile)) ||
    02220         IsDepotTile(v->tile) ||
    02221         IsTunnelTile(v->tile) ||
    02222         (v->type == VEH_TRAIN &&
    02223         !HasPowerOnRail(Train::From(v)->railtype, GetTileRailType(v->tile)))) {
    02224       continue;
    02225     }
    02226
    02227     /* The effect offset is relative to a point 4 units behind the vehicle's
    02228      * front (which is the center of an 8/8 vehicle). Shorter vehicles need a
    02229      * correction factor. */
    02230     if (v->type == VEH_TRAIN) effect_offset += (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2;
    02231
    02232     int x = _vehicle_smoke_pos[v->direction] * effect_offset;
    02233     int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
    02234
    02235     if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) {
    02236       x = -x;
    02237       y = -y;
    02238     }
    02239
    02240     switch (effect_type) {
    02241       case VE_TYPE_STEAM:
    02242         /* Steam smoke - amount is gradually falling until vehicle reaches its maximum speed, after that it's normal.
    02243          * Details: while vehicle's current speed is gradually increasing, steam plumes' density decreases by one third each
    02244          * third of its maximum speed spectrum. Steam emission finally normalises at very close to vehicle's maximum speed.
    02245          * REGULATION:
    02246          * - instead of 1, 4 / 2^smoke_amount (max. 2) is used to provide sufficient regulation to steam puffs' amount. */
    02247         if (GB(v->tick_counter, 0, ((4 >> _settings_game.vehicle.smoke_amount) + ((this->cur_speed * 3) / this->vcache.cached_max_speed))) == 0) {
    02248           CreateEffectVehicleRel(v, x, y, 10, EV_STEAM_SMOKE);
    02249           sound = true;
    02250         }
    02251         break;
    02252
    02253       case VE_TYPE_DIESEL: {
    02254         /* Diesel smoke - thicker when vehicle is starting, gradually subsiding till it reaches its maximum speed
    02255          * when smoke emission stops.
    02256          * Details: Vehicle's (max.) speed spectrum is divided into 32 parts. When max. speed is reached, chance for smoke
    02257          * emission erodes by 32 (1/4). For trains, power and weight come in handy too to either increase smoke emission in
    02258          * 6 steps (1000HP each) if the power is low or decrease smoke emission in 6 steps (512 tonnes each) if the train
    02259          * isn't overweight. Power and weight contributions are expressed in a way that neither extreme power, nor
    02260          * extreme weight can ruin the balance (e.g. FreightWagonMultiplier) in the formula. When the vehicle reaches
    02261          * maximum speed no diesel_smoke is emitted.
    02262          * REGULATION:
    02263          * - up to which speed a diesel vehicle is emitting smoke (with reduced/small setting only until 1/2 of max_speed),
    02264          * - in Chance16 - the last value is 512 / 2^smoke_amount (max. smoke when 128 = smoke_amount of 2). */
    02265         int power_weight_effect = 0;
    02266         if (v->type == VEH_TRAIN) {
    02267           power_weight_effect = (32 >> (Train::From(this)->gcache.cached_power >> 10)) - (32 >> (Train::From(this)->gcache.cached_weight >> 9));
    02268         }
    02269         if (this->cur_speed < (this->vcache.cached_max_speed >> (2 >> _settings_game.vehicle.smoke_amount)) &&
    02270             Chance16((64 - ((this->cur_speed << 5) / this->vcache.cached_max_speed) + power_weight_effect), (512 >> _settings_game.vehicle.smoke_amount))) {
    02271           CreateEffectVehicleRel(v, x, y, 10, EV_DIESEL_SMOKE);
    02272           sound = true;
    02273         }
    02274         break;
    02275       }
    02276
    02277       case VE_TYPE_ELECTRIC:
    02278         /* Electric train's spark - more often occurs when train is departing (more load)
    02279          * Details: Electric locomotives are usually at least twice as powerful as their diesel counterparts, so spark
    02280          * emissions are kept simple. Only when starting, creating huge force are sparks more likely to happen, but when
    02281          * reaching its max. speed, quarter by quarter of it, chance decreases untill the usuall 2,22% at train's top speed.
    02282          * REGULATION:
    02283          * - in Chance16 the last value is 360 / 2^smoke_amount (max. sparks when 90 = smoke_amount of 2). */
    02284         if (GB(v->tick_counter, 0, 2) == 0 &&
    02285             Chance16((6 - ((this->cur_speed << 2) / this->vcache.cached_max_speed)), (360 >> _settings_game.vehicle.smoke_amount))) {
    02286           CreateEffectVehicleRel(v, x, y, 10, EV_ELECTRIC_SPARK);
    02287           sound = true;
    02288         }
    02289         break;
    02290
    02291       default:
    02292         break;
    02293     }
    02294   } while ((v = v->Next()) != NULL);
    02295
    02296   if (sound) PlayVehicleSound(this, VSE_VISUAL_EFFECT);
    02297 }
    02298
    02303 void Vehicle::SetNext(Vehicle *next)
    02304 {
    02305   assert(this != next);
    02306
    02307   if (this->next != NULL) {
    02308     /* We had an old next vehicle. Update the first and previous pointers */
    02309     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
    02310       v->first = this->next;
    02311     }
    02312     this->next->previous = NULL;
    02313   }
    02314
    02315   this->next = next;
    02316
    02317   if (this->next != NULL) {
    02318     /* A new next vehicle. Update the first and previous pointers */
    02319     if (this->next->previous != NULL) this->next->previous->next = NULL;
    02320     this->next->previous = this;
    02321     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
    02322       v->first = this->first;
    02323     }
    02324   }
    02325 }
    02326
    02332 void Vehicle::AddToShared(Vehicle *shared_chain)
    02333 {
    02334   assert(this->previous_shared == NULL && this->next_shared == NULL);
    02335
    02336   if (shared_chain->orders.list == NULL) {
    02337     assert(shared_chain->previous_shared == NULL);
    02338     assert(shared_chain->next_shared == NULL);
    02339     this->orders.list = shared_chain->orders.list = new OrderList(NULL, shared_chain);
    02340   }
    02341
    02342   this->next_shared     = shared_chain->next_shared;
    02343   this->previous_shared = shared_chain;
    02344
    02345   shared_chain->next_shared = this;
    02346
    02347   if (this->next_shared != NULL) this->next_shared->previous_shared = this;
    02348
    02349   shared_chain->orders.list->AddVehicle(this);
    02350 }
    02351
    02355 void Vehicle::RemoveFromShared()
    02356 {
    02357   /* Remember if we were first and the old window number before RemoveVehicle()
    02358    * as this changes first if needed. */
    02359   bool were_first = (this->FirstShared() == this);
    02360   VehicleListIdentifier vli(VL_SHARED_ORDERS, this->type, this->owner, this->FirstShared()->index);
    02361
    02362   this->orders.list->RemoveVehicle(this);
    02363
    02364   if (!were_first) {
    02365     /* We are not the first shared one, so only relink our previous one. */
    02366     this->previous_shared->next_shared = this->NextShared();
    02367   }
    02368
    02369   if (this->next_shared != NULL) this->next_shared->previous_shared = this->previous_shared;
    02370
    02371
    02372   if (this->orders.list->GetNumVehicles() == 1) {
    02373     /* When there is only one vehicle, remove the shared order list window. */
    02374     DeleteWindowById(GetWindowClassForVehicleType(this->type), vli.Pack());
    02375     InvalidateVehicleOrder(this->FirstShared(), 0);
    02376   } else if (were_first) {
    02377     /* If we were the first one, update to the new first one.
    02378      * Note: FirstShared() is already the new first */
    02379     InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.Pack(), this->FirstShared()->index | (1U << 31));
    02380   }
    02381
    02382   this->next_shared     = NULL;
    02383   this->previous_shared = NULL;
    02384 }
    02385
    02386 void VehiclesYearlyLoop()
    02387 {
    02388   Vehicle *v;
    02389   FOR_ALL_VEHICLES(v) {
    02390     if (v->IsPrimaryVehicle()) {
    02391       /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
    02392       Money profit = v->GetDisplayProfitThisYear();
    02393       if (v->age >= 730 && profit < 0) {
    02394         if (_settings_client.gui.vehicle_income_warn && v->owner == _local_company) {
    02395           SetDParam(0, v->index);
    02396           SetDParam(1, profit);
    02397           AddVehicleNewsItem(
    02398             STR_NEWS_VEHICLE_IS_UNPROFITABLE,
    02399             NS_ADVICE,
    02400             v->index
    02401           );
    02402         }
    02403         AI::NewEvent(v->owner, new ScriptEventVehicleUnprofitable(v->index));
    02404       }
    02405
    02406       v->profit_last_year = v->profit_this_year;
    02407       v->profit_this_year = 0;
    02408       SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    02409     }
    02410   }
    02411   GroupStatistics::UpdateProfits();
    02412   SetWindowClassesDirty(WC_TRAINS_LIST);
    02413   SetWindowClassesDirty(WC_SHIPS_LIST);
    02414   SetWindowClassesDirty(WC_ROADVEH_LIST);
    02415   SetWindowClassesDirty(WC_AIRCRAFT_LIST);
    02416 }
    02417
    02418
    02428 bool CanVehicleUseStation(EngineID engine_type, const Station *st)
    02429 {
    02430   const Engine *e = Engine::GetIfValid(engine_type);
    02431   assert(e != NULL);
    02432
    02433   switch (e->type) {
    02434     case VEH_TRAIN:
    02435       return (st->facilities & FACIL_TRAIN) != 0;
    02436
    02437     case VEH_ROAD:
    02438       /* For road vehicles we need the vehicle to know whether it can actually
    02439        * use the station, but if it doesn't have facilities for RVs it is
    02440        * certainly not possible that the station can be used. */
    02441       return (st->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP)) != 0;
    02442
    02443     case VEH_SHIP:
    02444       return (st->facilities & FACIL_DOCK) != 0;
    02445
    02446     case VEH_AIRCRAFT:
    02447       return (st->facilities & FACIL_AIRPORT) != 0 &&
    02448           (st->airport.GetFTA()->flags & (e->u.air.subtype & AIR_CTOL ? AirportFTAClass::AIRPLANES : AirportFTAClass::HELICOPTERS)) != 0;
    02449
    02450     default:
    02451       return false;
    02452   }
    02453 }
    02454
    02461 bool CanVehicleUseStation(const Vehicle *v, const Station *st)
    02462 {
    02463   if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != NULL;
    02464
    02465   return CanVehicleUseStation(v->engine_type, st);
    02466 }
    02467
    02473 GroundVehicleCache *Vehicle::GetGroundVehicleCache()
    02474 {
    02475   assert(this->IsGroundVehicle());
    02476   if (this->type == VEH_TRAIN) {
    02477     return &Train::From(this)->gcache;
    02478   } else {
    02479     return &RoadVehicle::From(this)->gcache;
    02480   }
    02481 }
    02482
    02488 const GroundVehicleCache *Vehicle::GetGroundVehicleCache() const
    02489 {
    02490   assert(this->IsGroundVehicle());
    02491   if (this->type == VEH_TRAIN) {
    02492     return &Train::From(this)->gcache;
    02493   } else {
    02494     return &RoadVehicle::From(this)->gcache;
    02495   }
    02496 }
    02497
    02503 uint16 &Vehicle::GetGroundVehicleFlags()
    02504 {
    02505   assert(this->IsGroundVehicle());
    02506   if (this->type == VEH_TRAIN) {
    02507     return Train::From(this)->gv_flags;
    02508   } else {
    02509     return RoadVehicle::From(this)->gv_flags;
    02510   }
    02511 }
    02512
    02518 const uint16 &Vehicle::GetGroundVehicleFlags() const
    02519 {
    02520   assert(this->IsGroundVehicle());
    02521   if (this->type == VEH_TRAIN) {
    02522     return Train::From(this)->gv_flags;
    02523   } else {
    02524     return RoadVehicle::From(this)->gv_flags;
    02525   }
    02526 }
    02527
    02536 void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8 num_vehicles)
    02537 {
    02538   if (v->type == VEH_TRAIN) {
    02539     Train *u = Train::From(v);
    02540     /* Only include whole vehicles, so start with the first articulated part */
    02541     u = u->GetFirstEnginePart();
    02542
    02543     /* Include num_vehicles vehicles, not counting articulated parts */
    02544     for (; u != NULL && num_vehicles > 0; num_vehicles--) {
    02545       do {
    02546         /* Include current vehicle in the selection. */
    02547         set.Include(u->index);
    02548
    02549         /* If the vehicle is multiheaded, add the other part too. */
    02550         if (u->IsMultiheaded()) set.Include(u->other_multiheaded_part->index);
    02551
    02552         u = u->Next();
    02553       } while (u != NULL && u->IsArticulatedPart());
    02554     }
    02555   }
    02556 }