# vehicle.cpp

Go to the documentation of this file.

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