# vehicle.cpp

Go to the documentation of this file.

    00001 /* $Id: vehicle.cpp 19223 2010-02-23 23:26:37Z 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 "debug.h"
    00015 #include "roadveh.h"
    00016 #include "ship.h"
    00017 #include "spritecache.h"
    00018 #include "landscape.h"
    00019 #include "timetable.h"
    00020 #include "viewport_func.h"
    00021 #include "news_func.h"
    00022 #include "command_func.h"
    00023 #include "company_func.h"
    00024 #include "vehicle_gui.h"
    00025 #include "train.h"
    00026 #include "aircraft.h"
    00027 #include "newgrf_engine.h"
    00028 #include "newgrf_sound.h"
    00029 #include "newgrf_station.h"
    00030 #include "group.h"
    00031 #include "group_gui.h"
    00032 #include "strings_func.h"
    00033 #include "zoom_func.h"
    00034 #include "functions.h"
    00035 #include "date_func.h"
    00036 #include "window_func.h"
    00037 #include "vehicle_func.h"
    00038 #include "autoreplace_func.h"
    00039 #include "autoreplace_gui.h"
    00040 #include "station_base.h"
    00041 #include "ai/ai.hpp"
    00042 #include "core/smallmap_type.hpp"
    00043 #include "depot_func.h"
    00044 #include "network/network.h"
    00045 #include "core/pool_func.hpp"
    00046 #include "economy_base.h"
    00047 #include "articulated_vehicles.h"
    00048 #include "roadstop_base.h"
    00049 #include "core/random_func.hpp"
    00050 #include "engine_base.h"
    00051 #include "newgrf.h"
    00052
    00053 #include "table/sprites.h"
    00054 #include "table/strings.h"
    00055
    00056 #define GEN_HASH(x, y) ((GB((y), 6, 6) << 6) + GB((x), 7, 6))
    00057
    00058 VehicleID _vehicle_id_ctr_day;
    00059 const Vehicle *_place_clicked_vehicle;
    00060 VehicleID _new_vehicle_id;
    00061 uint16 _returned_refit_capacity;
    00062 byte _age_cargo_skip_counter;
    00063
    00064
    00065 /* Initialize the vehicle-pool */
    00066 VehiclePool _vehicle_pool("Vehicle");
    00067 INSTANTIATE_POOL_METHODS(Vehicle)
    00068
    00069
    00073 bool Vehicle::NeedsAutorenewing(const Company *c) const
    00074 {
    00075   /* We can always generate the Company pointer when we have the vehicle.
    00076    * However this takes time and since the Company pointer is often present
    00077    * when this function is called then it's faster to pass the pointer as an
    00078    * argument rather than finding it again. */
    00079   assert(c == Company::Get(this->owner));
    00080
    00081   if (!c->settings.engine_renew) return false;
    00082   if (this->age - this->max_age < (c->settings.engine_renew_months * 30)) return false;
    00083   if (this->age == 0) return false; // rail cars don't age and lacks a max age
    00084
    00085   return true;
    00086 }
    00087
    00088 void VehicleServiceInDepot(Vehicle *v)
    00089 {
    00090   v->date_of_last_service = _date;
    00091   v->breakdowns_since_last_service = 0;
    00092   v->reliability = Engine::Get(v->engine_type)->reliability;
    00093   SetWindowDirty(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
    00094 }
    00095
    00096 bool Vehicle::NeedsServicing() const
    00097 {
    00098   /* Stopped or crashed vehicles will not move, as such making unmovable
    00099    * vehicles to go for service is lame. */
    00100   if (this->vehstatus & (VS_STOPPED | VS_CRASHED)) return false;
    00101
    00102   /* Are we ready for the next service cycle? */
    00103   const Company *c = Company::Get(this->owner);
    00104   if (c->settings.vehicle.servint_ispercent ?
    00105       (this->reliability >= Engine::Get(this->engine_type)->reliability * (100 - this->service_interval) / 100) :
    00106       (this->date_of_last_service + this->service_interval >= _date)) {
    00107     return false;
    00108   }
    00109
    00110   /* If we're servicing anyway, because we have not disabled servicing when
    00111    * there are no breakdowns or we are playing with breakdowns, bail out. */
    00112   if (!_settings_game.order.no_servicing_if_no_breakdowns ||
    00113       _settings_game.difficulty.vehicle_breakdowns != 0) {
    00114     return true;
    00115   }
    00116
    00117   /* Test whether there is some pending autoreplace.
    00118    * Note: We do this after the service-interval test.
    00119    * There are a lot more reasons for autoreplace to fail than we can test here reasonably. */
    00120   bool pending_replace = false;
    00121   Money needed_money = c->settings.engine_renew_money;
    00122   if (needed_money > c->money) return false;
    00123
    00124   for (const Vehicle *v = this; v != NULL; v = (v->type == VEH_TRAIN) ? Train::From(v)->GetNextUnit() : NULL) {
    00125     EngineID new_engine = EngineReplacementForCompany(c, v->engine_type, v->group_id);
    00126
    00127     /* Check engine availability */
    00128     if (new_engine == INVALID_ENGINE || !HasBit(Engine::Get(new_engine)->company_avail, v->owner)) continue;
    00129
    00130     /* Check refittability */
    00131     uint32 available_cargo_types, union_mask;
    00132     GetArticulatedRefitMasks(new_engine, true, &union_mask, &available_cargo_types);
    00133     /* Is there anything to refit? */
    00134     if (union_mask != 0) {
    00135       CargoID cargo_type;
    00136       /* We cannot refit to mixed cargos in an automated way */
    00137       if (IsArticulatedVehicleCarryingDifferentCargos(v, &cargo_type)) continue;
    00138
    00139       /* Did the old vehicle carry anything? */
    00140       if (cargo_type != CT_INVALID) {
    00141         /* We can't refit the vehicle to carry the cargo we want */
    00142         if (!HasBit(available_cargo_types, cargo_type)) continue;
    00143       }
    00144     }
    00145
    00146     /* Check money.
    00147      * We want 2*(the price of the new vehicle) without looking at the value of the vehicle we are going to sell. */
    00148     pending_replace = true;
    00149     needed_money += 2 * Engine::Get(new_engine)->GetCost();
    00150     if (needed_money > c->money) return false;
    00151   }
    00152
    00153   return pending_replace;
    00154 }
    00155
    00156 bool Vehicle::NeedsAutomaticServicing() const
    00157 {
    00158   if (_settings_game.order.gotodepot && VehicleHasDepotOrders(this)) return false;
    00159   if (this->current_order.IsType(OT_LOADING))            return false;
    00160   if (this->current_order.IsType(OT_GOTO_DEPOT) && this->current_order.GetDepotOrderType() != ODTFB_SERVICE) return false;
    00161   return NeedsServicing();
    00162 }
    00163
    00164 uint Vehicle::Crash(bool flooded)
    00165 {
    00166   assert((this->vehstatus & VS_CRASHED) == 0);
    00167   assert(this->Previous() == NULL); // IsPrimaryVehicle fails for free-wagon-chains
    00168
    00169   uint pass = 0;
    00170   /* crash all wagons, and count passengers */
    00171   for (Vehicle *v = this; v != NULL; v = v->Next()) {
    00172     if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) pass += v->cargo.Count();
    00173     v->vehstatus |= VS_CRASHED;
    00174     MarkSingleVehicleDirty(v);
    00175   }
    00176
    00177   /* Dirty some windows */
    00178   InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
    00179   SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    00180   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
    00181   SetWindowDirty(WC_VEHICLE_DEPOT, this->tile);
    00182
    00183   return pass;
    00184 }
    00185
    00186
    00195 void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical)
    00196 {
    00197   const Engine *e = Engine::Get(engine);
    00198   uint32 grfid = e->grffile->grfid;
    00199   GRFConfig *grfconfig = GetGRFConfig(grfid);
    00200
    00201   if (!HasBit(grfconfig->grf_bugs, bug_type)) {
    00202     SetBit(grfconfig->grf_bugs, bug_type);
    00203     SetDParamStr(0, grfconfig->name);
    00204     SetDParam(1, engine);
    00205     ShowErrorMessage(part1, part2, 0, 0, true);
    00206     if (!_networking) DoCommand(0, critical ? PM_PAUSED_ERROR : PM_PAUSED_NORMAL, 1, DC_EXEC, CMD_PAUSE);
    00207   }
    00208
    00209   /* debug output */
    00210   char buffer[512];
    00211
    00212   SetDParamStr(0, grfconfig->name);
    00213   GetString(buffer, part1, lastof(buffer));
    00214   DEBUG(grf, 0, "%s", buffer + 3);
    00215
    00216   SetDParam(1, engine);
    00217   GetString(buffer, part2, lastof(buffer));
    00218   DEBUG(grf, 0, "%s", buffer + 3);
    00219 }
    00220
    00221 static Vehicle *EnsureNoVehicleProcZ(Vehicle *v, void *data)
    00222 {
    00223   byte z = *(byte*)data;
    00224
    00225   if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
    00226   if (v->z_pos > z) return NULL;
    00227
    00228   _error_message = STR_ERROR_TRAIN_IN_THE_WAY + v->type;
    00229   return v;
    00230 }
    00231
    00232 bool EnsureNoVehicleOnGround(TileIndex tile)
    00233 {
    00234   byte z = GetTileMaxZ(tile);
    00235   return !HasVehicleOnPos(tile, &z, &EnsureNoVehicleProcZ);
    00236 }
    00237
    00239 static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
    00240 {
    00241   if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) return NULL;
    00242   if (v == (const Vehicle *)data) return NULL;
    00243
    00244   _error_message = STR_ERROR_TRAIN_IN_THE_WAY + v->type;
    00245   return v;
    00246 }
    00247
    00255 bool HasVehicleOnTunnelBridge(TileIndex tile, TileIndex endtile, const Vehicle *ignore)
    00256 {
    00257   return HasVehicleOnPos(tile, (void *)ignore, &GetVehicleTunnelBridgeProc) ||
    00258       HasVehicleOnPos(endtile, (void *)ignore, &GetVehicleTunnelBridgeProc);
    00259 }
    00260
    00261
    00262 Vehicle::Vehicle(VehicleType type)
    00263 {
    00264   this->type               = type;
    00265   this->coord.left         = INVALID_COORD;
    00266   this->group_id           = DEFAULT_GROUP;
    00267   this->fill_percent_te_id = INVALID_TE_ID;
    00268   this->first              = this;
    00269   this->colourmap          = PAL_NONE;
    00270 }
    00271
    00276 byte VehicleRandomBits()
    00277 {
    00278   return GB(Random(), 0, 8);
    00279 }
    00280
    00281 /* Size of the hash, 6 = 64 x 64, 7 = 128 x 128. Larger sizes will (in theory) reduce hash
    00282  * lookup times at the expense of memory usage. */
    00283 const int HASH_BITS = 7;
    00284 const int HASH_SIZE = 1 << HASH_BITS;
    00285 const int HASH_MASK = HASH_SIZE - 1;
    00286 const int TOTAL_HASH_SIZE = 1 << (HASH_BITS * 2);
    00287 const int TOTAL_HASH_MASK = TOTAL_HASH_SIZE - 1;
    00288
    00289 /* Resolution of the hash, 0 = 1*1 tile, 1 = 2*2 tiles, 2 = 4*4 tiles, etc.
    00290  * Profiling results show that 0 is fastest. */
    00291 const int HASH_RES = 0;
    00292
    00293 static Vehicle *_new_vehicle_position_hash[TOTAL_HASH_SIZE];
    00294
    00295 static Vehicle *VehicleFromHash(int xl, int yl, int xu, int yu, void *data, VehicleFromPosProc *proc, bool find_first)
    00296 {
    00297   for (int y = yl; ; y = (y + (1 << HASH_BITS)) & (HASH_MASK << HASH_BITS)) {
    00298     for (int x = xl; ; x = (x + 1) & HASH_MASK) {
    00299       Vehicle *v = _new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
    00300       for (; v != NULL; v = v->next_new_hash) {
    00301         Vehicle *a = proc(v, data);
    00302         if (find_first && a != NULL) return a;
    00303       }
    00304       if (x == xu) break;
    00305     }
    00306     if (y == yu) break;
    00307   }
    00308
    00309   return NULL;
    00310 }
    00311
    00312
    00324 static Vehicle *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc, bool find_first)
    00325 {
    00326   const int COLL_DIST = 6;
    00327
    00328   /* Hash area to scan is from xl,yl to xu,yu */
    00329   int xl = GB((x - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
    00330   int xu = GB((x + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
    00331   int yl = GB((y - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
    00332   int yu = GB((y + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
    00333
    00334   return VehicleFromHash(xl, yl, xu, yu, data, proc, find_first);
    00335 }
    00336
    00351 void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
    00352 {
    00353   VehicleFromPosXY(x, y, data, proc, false);
    00354 }
    00355
    00367 bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
    00368 {
    00369   return VehicleFromPosXY(x, y, data, proc, true) != NULL;
    00370 }
    00371
    00382 static Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc, bool find_first)
    00383 {
    00384   int x = GB(TileX(tile), HASH_RES, HASH_BITS);
    00385   int y = GB(TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS;
    00386
    00387   Vehicle *v = _new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
    00388   for (; v != NULL; v = v->next_new_hash) {
    00389     if (v->tile != tile) continue;
    00390
    00391     Vehicle *a = proc(v, data);
    00392     if (find_first && a != NULL) return a;
    00393   }
    00394
    00395   return NULL;
    00396 }
    00397
    00411 void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
    00412 {
    00413   VehicleFromPos(tile, data, proc, false);
    00414 }
    00415
    00426 bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
    00427 {
    00428   return VehicleFromPos(tile, data, proc, true) != NULL;
    00429 }
    00430
    00431
    00432 static void UpdateNewVehiclePosHash(Vehicle *v, bool remove)
    00433 {
    00434   Vehicle **old_hash = v->old_new_hash;
    00435   Vehicle **new_hash;
    00436
    00437   if (remove) {
    00438     new_hash = NULL;
    00439   } else {
    00440     int x = GB(TileX(v->tile), HASH_RES, HASH_BITS);
    00441     int y = GB(TileY(v->tile), HASH_RES, HASH_BITS) << HASH_BITS;
    00442     new_hash = &_new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
    00443   }
    00444
    00445   if (old_hash == new_hash) return;
    00446
    00447   /* Remove from the old position in the hash table */
    00448   if (old_hash != NULL) {
    00449     if (v->next_new_hash != NULL) v->next_new_hash->prev_new_hash = v->prev_new_hash;
    00450     *v->prev_new_hash = v->next_new_hash;
    00451   }
    00452
    00453   /* Insert vehicle at beginning of the new position in the hash table */
    00454   if (new_hash != NULL) {
    00455     v->next_new_hash = *new_hash;
    00456     if (v->next_new_hash != NULL) v->next_new_hash->prev_new_hash = &v->next_new_hash;
    00457     v->prev_new_hash = new_hash;
    00458     *new_hash = v;
    00459   }
    00460
    00461   /* Remember current hash position */
    00462   v->old_new_hash = new_hash;
    00463 }
    00464
    00465 static Vehicle *_vehicle_position_hash[0x1000];
    00466
    00467 static void UpdateVehiclePosHash(Vehicle *v, int x, int y)
    00468 {
    00469   UpdateNewVehiclePosHash(v, x == INVALID_COORD);
    00470
    00471   Vehicle **old_hash, **new_hash;
    00472   int old_x = v->coord.left;
    00473   int old_y = v->coord.top;
    00474
    00475   new_hash = (x == INVALID_COORD) ? NULL : &_vehicle_position_hash[GEN_HASH(x, y)];
    00476   old_hash = (old_x == INVALID_COORD) ? NULL : &_vehicle_position_hash[GEN_HASH(old_x, old_y)];
    00477
    00478   if (old_hash == new_hash) return;
    00479
    00480   /* remove from hash table? */
    00481   if (old_hash != NULL) {
    00482     if (v->next_hash != NULL) v->next_hash->prev_hash = v->prev_hash;
    00483     *v->prev_hash = v->next_hash;
    00484   }
    00485
    00486   /* insert into hash table? */
    00487   if (new_hash != NULL) {
    00488     v->next_hash = *new_hash;
    00489     if (v->next_hash != NULL) v->next_hash->prev_hash = &v->next_hash;
    00490     v->prev_hash = new_hash;
    00491     *new_hash = v;
    00492   }
    00493 }
    00494
    00495 void ResetVehiclePosHash()
    00496 {
    00497   Vehicle *v;
    00498   FOR_ALL_VEHICLES(v) { v->old_new_hash = NULL; }
    00499   memset(_vehicle_position_hash, 0, sizeof(_vehicle_position_hash));
    00500   memset(_new_vehicle_position_hash, 0, sizeof(_new_vehicle_position_hash));
    00501 }
    00502
    00503 void ResetVehicleColourMap()
    00504 {
    00505   Vehicle *v;
    00506   FOR_ALL_VEHICLES(v) { v->colourmap = PAL_NONE; }
    00507 }
    00508
    00513 typedef SmallMap<Vehicle *, bool, 4> AutoreplaceMap;
    00514 static AutoreplaceMap _vehicles_to_autoreplace;
    00515
    00516 void InitializeVehicles()
    00517 {
    00518   _vehicle_pool.CleanPool();
    00519   _cargo_payment_pool.CleanPool();
    00520
    00521   _age_cargo_skip_counter = 1;
    00522
    00523   _vehicles_to_autoreplace.Reset();
    00524   ResetVehiclePosHash();
    00525 }
    00526
    00527 uint CountVehiclesInChain(const Vehicle *v)
    00528 {
    00529   uint count = 0;
    00530   do count++; while ((v = v->Next()) != NULL);
    00531   return count;
    00532 }
    00533
    00537 bool Vehicle::IsEngineCountable() const
    00538 {
    00539   switch (this->type) {
    00540     case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft(); // don't count plane shadows and helicopter rotors
    00541     case VEH_TRAIN:
    00542       return !Train::From(this)->IsArticulatedPart() && // tenders and other articulated parts
    00543           !Train::From(this)->IsRearDualheaded(); // rear parts of multiheaded engines
    00544     case VEH_ROAD: return RoadVehicle::From(this)->IsRoadVehFront();
    00545     case VEH_SHIP: return true;
    00546     default: return false; // Only count company buildable vehicles
    00547   }
    00548 }
    00549
    00550 void Vehicle::PreDestructor()
    00551 {
    00552   if (CleaningPool()) return;
    00553
    00554   if (Station::IsValidID(this->last_station_visited)) {
    00555     Station::Get(this->last_station_visited)->loading_vehicles.remove(this);
    00556
    00557     HideFillingPercent(&this->fill_percent_te_id);
    00558
    00559     delete this->cargo_payment;
    00560   }
    00561
    00562   if (this->IsEngineCountable()) {
    00563     Company::Get(this->owner)->num_engines[this->engine_type]--;
    00564     if (this->owner == _local_company) InvalidateAutoreplaceWindow(this->engine_type, this->group_id);
    00565
    00566     DeleteGroupHighlightOfVehicle(this);
    00567     if (Group::IsValidID(this->group_id)) Group::Get(this->group_id)->num_engines[this->engine_type]--;
    00568     if (this->IsPrimaryVehicle()) DecreaseGroupNumVehicle(this->group_id);
    00569   }
    00570
    00571   if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) {
    00572     Aircraft *a = Aircraft::From(this);
    00573     Station *st = GetTargetAirportIfValid(a);
    00574     if (st != NULL) {
    00575       const AirportFTA *layout = st->Airport()->layout;
    00576       CLRBITS(st->airport_flags, layout[a->previous_pos].block | layout[a->pos].block);
    00577     }
    00578   }
    00579
    00580
    00581   if (this->type == VEH_ROAD && this->IsPrimaryVehicle()) {
    00582     RoadVehicle *v = RoadVehicle::From(this);
    00583     if (!(v->vehstatus & VS_CRASHED) && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
    00584       /* Leave the drive through roadstop, when you have not already left it. */
    00585       RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
    00586     }
    00587   }
    00588
    00589   if (this->Previous() == NULL) {
    00590     InvalidateWindowData(WC_VEHICLE_DEPOT, this->tile);
    00591   }
    00592
    00593   if (this->IsPrimaryVehicle()) {
    00594     DeleteWindowById(WC_VEHICLE_VIEW, this->index);
    00595     DeleteWindowById(WC_VEHICLE_ORDERS, this->index);
    00596     DeleteWindowById(WC_VEHICLE_REFIT, this->index);
    00597     DeleteWindowById(WC_VEHICLE_DETAILS, this->index);
    00598     DeleteWindowById(WC_VEHICLE_TIMETABLE, this->index);
    00599     SetWindowDirty(WC_COMPANY, this->owner);
    00600   }
    00601   InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
    00602
    00603   this->cargo.Truncate(0);
    00604   DeleteVehicleOrders(this);
    00605   DeleteDepotHighlightOfVehicle(this);
    00606
    00607   extern void StopGlobalFollowVehicle(const Vehicle *v);
    00608   StopGlobalFollowVehicle(this);
    00609
    00610   ReleaseDisastersTargetingVehicle(this->index);
    00611 }
    00612
    00613 Vehicle::~Vehicle()
    00614 {
    00615   free(this->name);
    00616
    00617   if (CleaningPool()) return;
    00618
    00619   /* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles,
    00620    * it may happen that vehicle chain is deleted when visible */
    00621   if (!(this->vehstatus & VS_HIDDEN)) MarkSingleVehicleDirty(this);
    00622
    00623   Vehicle *v = this->Next();
    00624   this->SetNext(NULL);
    00625
    00626   delete v;
    00627
    00628   UpdateVehiclePosHash(this, INVALID_COORD, 0);
    00629   DeleteVehicleNews(this->index, INVALID_STRING_ID);
    00630 }
    00631
    00635 void VehicleEnteredDepotThisTick(Vehicle *v)
    00636 {
    00637   /* Vehicle should stop in the depot if it was in 'stopping' state */
    00638   _vehicles_to_autoreplace[v] = !(v->vehstatus & VS_STOPPED);
    00639
    00640   /* We ALWAYS set the stopped state. Even when the vehicle does not plan on
    00641    * stopping in the depot, so we stop it to ensure that it will not reserve
    00642    * the path out of the depot before we might autoreplace it to a different
    00643    * engine. The new engine would not own the reserved path we store that we
    00644    * stopped the vehicle, so autoreplace can start it again */
    00645   v->vehstatus |= VS_STOPPED;
    00646 }
    00647
    00653 static void RunVehicleDayProc()
    00654 {
    00655   if (_game_mode != GM_NORMAL) return;
    00656
    00657   /* Run the day_proc for every DAY_TICKS vehicle starting at _date_fract. */
    00658   for (size_t i = _date_fract; i < Vehicle::GetPoolSize(); i += DAY_TICKS) {
    00659     Vehicle *v = Vehicle::Get(i);
    00660     if (v == NULL) continue;
    00661
    00662     /* Call the 32-day callback if needed */
    00663     if ((v->day_counter & 0x1F) == 0) {
    00664       uint16 callback = GetVehicleCallback(CBID_VEHICLE_32DAY_CALLBACK, 0, 0, v->engine_type, v);
    00665       if (callback != CALLBACK_FAILED) {
    00666         if (HasBit(callback, 0)) TriggerVehicle(v, VEHICLE_TRIGGER_CALLBACK_32); // Trigger vehicle trigger 10
    00667         if (HasBit(callback, 1)) v->colourmap = PAL_NONE;
    00668       }
    00669     }
    00670
    00671     /* This is called once per day for each vehicle, but not in the first tick of the day */
    00672     v->OnNewDay();
    00673   }
    00674 }
    00675
    00676 void CallVehicleTicks()
    00677 {
    00678   _vehicles_to_autoreplace.Clear();
    00679
    00680   _age_cargo_skip_counter = (_age_cargo_skip_counter == 0) ? 184 : (_age_cargo_skip_counter - 1);
    00681
    00682   RunVehicleDayProc();
    00683
    00684   Station *st;
    00685   FOR_ALL_STATIONS(st) LoadUnloadStation(st);
    00686
    00687   Vehicle *v;
    00688   FOR_ALL_VEHICLES(v) {
    00689     /* Vehicle could be deleted in this tick */
    00690     if (!v->Tick()) {
    00691       assert(Vehicle::Get(vehicle_index) == NULL);
    00692       continue;
    00693     }
    00694
    00695     assert(Vehicle::Get(vehicle_index) == v);
    00696
    00697     switch (v->type) {
    00698       default: break;
    00699
    00700       case VEH_TRAIN:
    00701       case VEH_ROAD:
    00702       case VEH_AIRCRAFT:
    00703       case VEH_SHIP:
    00704         if (_age_cargo_skip_counter == 0) v->cargo.AgeCargo();
    00705
    00706         if (v->type == VEH_TRAIN && Train::From(v)->IsWagon()) continue;
    00707         if (v->type == VEH_AIRCRAFT && v->subtype != AIR_HELICOPTER) continue;
    00708         if (v->type == VEH_ROAD && !RoadVehicle::From(v)->IsRoadVehFront()) continue;
    00709
    00710         v->motion_counter += v->cur_speed;
    00711         /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
    00712         if (GB(v->motion_counter, 0, 8) < v->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
    00713
    00714         /* Play an alterate running sound every 16 ticks */
    00715         if (GB(v->tick_counter, 0, 4) == 0) PlayVehicleSound(v, v->cur_speed > 0 ? VSE_RUNNING_16 : VSE_STOPPED_16);
    00716     }
    00717   }
    00718
    00719   for (AutoreplaceMap::iterator it = _vehicles_to_autoreplace.Begin(); it != _vehicles_to_autoreplace.End(); it++) {
    00720     v = it->first;
    00721     /* Autoreplace needs the current company set as the vehicle owner */
    00722     _current_company = v->owner;
    00723
    00724     /* Start vehicle if we stopped them in VehicleEnteredDepotThisTick()
    00725      * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that
    00726      * they are already leaving the depot again before being replaced. */
    00727     if (it->second) v->vehstatus &= ~VS_STOPPED;
    00728
    00729     /* Store the position of the effect as the vehicle pointer will become invalid later */
    00730     int x = v->x_pos;
    00731     int y = v->y_pos;
    00732     int z = v->z_pos;
    00733
    00734     const Company *c = Company::Get(_current_company);
    00735     SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, (Money)c->settings.engine_renew_money));
    00736     CommandCost res = DoCommand(0, v->index, 0, DC_EXEC, CMD_AUTOREPLACE_VEHICLE);
    00737     SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, -(Money)c->settings.engine_renew_money));
    00738
    00739     if (!IsLocalCompany()) continue;
    00740
    00741     if (res.Succeeded()) {
    00742       ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
    00743       continue;
    00744     }
    00745
    00746     StringID error_message = res.GetErrorMessage();
    00747     if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message == INVALID_STRING_ID) continue;
    00748
    00749     if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT;
    00750
    00751     StringID message;
    00752     if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
    00753       message = error_message;
    00754     } else {
    00755       message = STR_NEWS_VEHICLE_AUTORENEW_FAILED;
    00756     }
    00757
    00758     SetDParam(0, v->index);
    00759     SetDParam(1, error_message);
    00760     AddVehicleNewsItem(message, NS_ADVICE, v->index);
    00761   }
    00762
    00763   _current_company = OWNER_NONE;
    00764 }
    00765
    00766 static void DoDrawVehicle(const Vehicle *v)
    00767 {
    00768   SpriteID image = v->cur_image;
    00769   PaletteID pal = PAL_NONE;
    00770
    00771   if (v->vehstatus & VS_DEFPAL) pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
    00772
    00773   AddSortableSpriteToDraw(image, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
    00774     v->x_extent, v->y_extent, v->z_extent, v->z_pos, (v->vehstatus & VS_SHADOW) != 0);
    00775 }
    00776
    00777 void ViewportAddVehicles(DrawPixelInfo *dpi)
    00778 {
    00779   /* The bounding rectangle */
    00780   const int l = dpi->left;
    00781   const int r = dpi->left + dpi->width;
    00782   const int t = dpi->top;
    00783   const int b = dpi->top + dpi->height;
    00784
    00785   /* The hash area to scan */
    00786   int xl, xu, yl, yu;
    00787
    00788   if (dpi->width + 70 < (1 << (7 + 6))) {
    00789     xl = GB(l - 70, 7, 6);
    00790     xu = GB(r,      7, 6);
    00791   } else {
    00792     /* scan whole hash row */
    00793     xl = 0;
    00794     xu = 0x3F;
    00795   }
    00796
    00797   if (dpi->height + 70 < (1 << (6 + 6))) {
    00798     yl = GB(t - 70, 6, 6) << 6;
    00799     yu = GB(b,      6, 6) << 6;
    00800   } else {
    00801     /* scan whole column */
    00802     yl = 0;
    00803     yu = 0x3F << 6;
    00804   }
    00805
    00806   for (int y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
    00807     for (int x = xl;; x = (x + 1) & 0x3F) {
    00808       const Vehicle *v = _vehicle_position_hash[x + y]; // already masked & 0xFFF
    00809
    00810       while (v != NULL) {
    00811         if (!(v->vehstatus & VS_HIDDEN) &&
    00812             l <= v->coord.right &&
    00813             t <= v->coord.bottom &&
    00814             r >= v->coord.left &&
    00815             b >= v->coord.top) {
    00816           DoDrawVehicle(v);
    00817         }
    00818         v = v->next_hash;
    00819       }
    00820
    00821       if (x == xu) break;
    00822     }
    00823
    00824     if (y == yu) break;
    00825   }
    00826 }
    00827
    00828 Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y)
    00829 {
    00830   Vehicle *found = NULL, *v;
    00831   uint dist, best_dist = UINT_MAX;
    00832
    00833   if ((uint)(x -= vp->left) >= (uint)vp->width || (uint)(y -= vp->top) >= (uint)vp->height) return NULL;
    00834
    00835   x = ScaleByZoom(x, vp->zoom) + vp->virtual_left;
    00836   y = ScaleByZoom(y, vp->zoom) + vp->virtual_top;
    00837
    00838   FOR_ALL_VEHICLES(v) {
    00839     if ((v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0 &&
    00840         x >= v->coord.left && x <= v->coord.right &&
    00841         y >= v->coord.top && y <= v->coord.bottom) {
    00842
    00843       dist = max(
    00844         abs(((v->coord.left + v->coord.right) >> 1) - x),
    00845         abs(((v->coord.top + v->coord.bottom) >> 1) - y)
    00846       );
    00847
    00848       if (dist < best_dist) {
    00849         found = v;
    00850         best_dist = dist;
    00851       }
    00852     }
    00853   }
    00854
    00855   return found;
    00856 }
    00857
    00858 void DecreaseVehicleValue(Vehicle *v)
    00859 {
    00860   v->value -= v->value >> 8;
    00861   SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    00862 }
    00863
    00864 static const byte _breakdown_chance[64] = {
    00865     3,   3,   3,   3,   3,   3,   3,   3,
    00866     4,   4,   5,   5,   6,   6,   7,   7,
    00867     8,   8,   9,   9,  10,  10,  11,  11,
    00868    12,  13,  13,  13,  13,  14,  15,  16,
    00869    17,  19,  21,  25,  28,  31,  34,  37,
    00870    40,  44,  48,  52,  56,  60,  64,  68,
    00871    72,  80,  90, 100, 110, 120, 130, 140,
    00872   150, 170, 190, 210, 230, 250, 250, 250,
    00873 };
    00874
    00875 void CheckVehicleBreakdown(Vehicle *v)
    00876 {
    00877   int rel, rel_old;
    00878
    00879   /* decrease reliability */
    00880   v->reliability = rel = max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
    00881   if ((rel_old >> 8) != (rel >> 8)) SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    00882
    00883   if (v->breakdown_ctr != 0 || (v->vehstatus & VS_STOPPED) ||
    00884       _settings_game.difficulty.vehicle_breakdowns < 1 ||
    00885       v->cur_speed < 5 || _game_mode == GM_MENU) {
    00886     return;
    00887   }
    00888
    00889   uint32 r = Random();
    00890
    00891   /* increase chance of failure */
    00892   int chance = v->breakdown_chance + 1;
    00893   if (Chance16I(1, 25, r)) chance += 25;
    00894   v->breakdown_chance = min(255, chance);
    00895
    00896   /* calculate reliability value to use in comparison */
    00897   rel = v->reliability;
    00898   if (v->type == VEH_SHIP) rel += 0x6666;
    00899
    00900   /* reduced breakdowns? */
    00901   if (_settings_game.difficulty.vehicle_breakdowns == 1) rel += 0x6666;
    00902
    00903   /* check if to break down */
    00904   if (_breakdown_chance[(uint)min(rel, 0xffff) >> 10] <= v->breakdown_chance) {
    00905     v->breakdown_ctr    = GB(r, 16, 6) + 0x3F;
    00906     v->breakdown_delay  = GB(r, 24, 7) + 0x80;
    00907     v->breakdown_chance = 0;
    00908   }
    00909 }
    00910
    00911 void AgeVehicle(Vehicle *v)
    00912 {
    00913   if (v->age < 65535) v->age++;
    00914
    00915   int age = v->age - v->max_age;
    00916   if (age == DAYS_IN_LEAP_YEAR * 0 || age == DAYS_IN_LEAP_YEAR * 1 ||
    00917       age == DAYS_IN_LEAP_YEAR * 2 || age == DAYS_IN_LEAP_YEAR * 3 || age == DAYS_IN_LEAP_YEAR * 4) {
    00918     v->reliability_spd_dec <<= 1;
    00919   }
    00920
    00921   SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    00922
    00923   /* Don't warn about non-primary or not ours vehicles or vehicles that are crashed */
    00924   if (v->Previous() != NULL || v->owner != _local_company || (v->vehstatus & VS_CRASHED) != 0) return;
    00925
    00926   /* Don't warn if a renew is active */
    00927   if (Company::Get(v->owner)->settings.engine_renew && Engine::Get(v->engine_type)->company_avail != 0) return;
    00928
    00929   StringID str;
    00930   if (age == -DAYS_IN_LEAP_YEAR) {
    00931     str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
    00932   } else if (age == 0) {
    00933     str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
    00934   } else if (age > 0 && (age % DAYS_IN_LEAP_YEAR) == 0) {
    00935     str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
    00936   } else {
    00937     return;
    00938   }
    00939
    00940   SetDParam(0, v->index);
    00941   AddVehicleNewsItem(str, NS_ADVICE, v->index);
    00942 }
    00943
    00950 uint8 CalcPercentVehicleFilled(const Vehicle *v, StringID *colour)
    00951 {
    00952   int count = 0;
    00953   int max = 0;
    00954   int cars = 0;
    00955   int unloading = 0;
    00956   bool loading = false;
    00957
    00958   const Vehicle *u = v;
    00959   const Station *st = v->last_station_visited != INVALID_STATION ? Station::Get(v->last_station_visited) : NULL;
    00960
    00961   /* Count up max and used */
    00962   for (; v != NULL; v = v->Next()) {
    00963     count += v->cargo.Count();
    00964     max += v->cargo_cap;
    00965     if (v->cargo_cap != 0 && colour != NULL) {
    00966       unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0;
    00967       loading |= !(u->current_order.GetLoadType() & OLFB_NO_LOAD) && st->goods[v->cargo_type].days_since_pickup != 255;
    00968       cars++;
    00969     }
    00970   }
    00971
    00972   if (colour != NULL) {
    00973     if (unloading == 0 && loading) {
    00974       *colour = STR_PERCENT_UP;
    00975     } else if (cars == unloading || !loading) {
    00976       *colour = STR_PERCENT_DOWN;
    00977     } else {
    00978       *colour = STR_PERCENT_UP_DOWN;
    00979     }
    00980   }
    00981
    00982   /* Train without capacity */
    00983   if (max == 0) return 100;
    00984
    00985   /* Return the percentage */
    00986   return (count * 100) / max;
    00987 }
    00988
    00989 void VehicleEnterDepot(Vehicle *v)
    00990 {
    00991   /* Always work with the front of the vehicle */
    00992   assert(v == v->First());
    00993
    00994   switch (v->type) {
    00995     case VEH_TRAIN: {
    00996       Train *t = Train::From(v);
    00997       SetWindowClassesDirty(WC_TRAINS_LIST);
    00998       /* Clear path reservation */
    00999       SetDepotReservation(t->tile, false);
    01000       if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(t->tile);
    01001
    01002       UpdateSignalsOnSegment(t->tile, INVALID_DIAGDIR, t->owner);
    01003       t->wait_counter = 0;
    01004       ClrBit(t->flags, VRF_TOGGLE_REVERSE);
    01005       t->ConsistChanged(true);
    01006       break;
    01007     }
    01008
    01009     case VEH_ROAD:
    01010       SetWindowClassesDirty(WC_ROADVEH_LIST);
    01011       break;
    01012
    01013     case VEH_SHIP:
    01014       SetWindowClassesDirty(WC_SHIPS_LIST);
    01015       Ship::From(v)->state = TRACK_BIT_DEPOT;
    01016       RecalcShipStuff(v);
    01017       break;
    01018
    01019     case VEH_AIRCRAFT:
    01020       SetWindowClassesDirty(WC_AIRCRAFT_LIST);
    01021       HandleAircraftEnterHangar(Aircraft::From(v));
    01022       break;
    01023     default: NOT_REACHED();
    01024   }
    01025
    01026   if (v->type != VEH_TRAIN) {
    01027     /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
    01028      * 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 */
    01029     InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
    01030   }
    01031   SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
    01032
    01033   v->vehstatus |= VS_HIDDEN;
    01034   v->cur_speed = 0;
    01035
    01036   VehicleServiceInDepot(v);
    01037
    01038   TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
    01039
    01040   if (v->current_order.IsType(OT_GOTO_DEPOT)) {
    01041     SetWindowDirty(WC_VEHICLE_VIEW, v->index);
    01042
    01043     const Order *real_order = v->GetOrder(v->cur_order_index);
    01044     Order t = v->current_order;
    01045     v->current_order.MakeDummy();
    01046
    01047     /* Test whether we are heading for this depot. If not, do nothing.
    01048      * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
    01049     if ((t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) &&
    01050         real_order != NULL && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) &&
    01051         (v->type == VEH_AIRCRAFT ? t.GetDestination() != GetStationIndex(v->tile) : v->dest_tile != v->tile)) {
    01052       /* We are heading for another depot, keep driving. */
    01053       return;
    01054     }
    01055
    01056     if (t.IsRefit()) {
    01057       _current_company = v->owner;
    01058       CommandCost cost = DoCommand(v->tile, v->index, t.GetRefitCargo() | t.GetRefitSubtype() << 8, DC_EXEC, GetCmdRefitVeh(v));
    01059
    01060       if (cost.Failed()) {
    01061         _vehicles_to_autoreplace[v] = false;
    01062         if (v->owner == _local_company) {
    01063           /* Notify the user that we stopped the vehicle */
    01064           SetDParam(0, v->index);
    01065           AddVehicleNewsItem(STR_NEWS_ORDER_REFIT_FAILED, NS_ADVICE, v->index);
    01066         }
    01067       } else if (v->owner == _local_company && cost.GetCost() != 0) {
    01068         ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
    01069       }
    01070     }
    01071
    01072     if (t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
    01073       /* Part of orders */
    01074       UpdateVehicleTimetable(v, true);
    01075       v->IncrementOrderIndex();
    01076     }
    01077     if (t.GetDepotActionType() & ODATFB_HALT) {
    01078       /* Vehicles are always stopped on entering depots. Do not restart this one. */
    01079       _vehicles_to_autoreplace[v] = false;
    01080       if (v->owner == _local_company) {
    01081         SetDParam(0, v->index);
    01082         AddVehicleNewsItem(STR_NEWS_TRAIN_IS_WAITING + v->type, NS_ADVICE, v->index);
    01083       }
    01084       AI::NewEvent(v->owner, new AIEventVehicleWaitingInDepot(v->index));
    01085     }
    01086   }
    01087 }
    01088
    01089
    01097 void VehicleMove(Vehicle *v, bool update_viewport)
    01098 {
    01099   int img = v->cur_image;
    01100   Point pt = RemapCoords(v->x_pos + v->x_offs, v->y_pos + v->y_offs, v->z_pos);
    01101   const Sprite *spr = GetSprite(img, ST_NORMAL);
    01102
    01103   pt.x += spr->x_offs;
    01104   pt.y += spr->y_offs;
    01105
    01106   UpdateVehiclePosHash(v, pt.x, pt.y);
    01107
    01108   Rect old_coord = v->coord;
    01109   v->coord.left   = pt.x;
    01110   v->coord.top    = pt.y;
    01111   v->coord.right  = pt.x + spr->width + 2;
    01112   v->coord.bottom = pt.y + spr->height + 2;
    01113
    01114   if (update_viewport) {
    01115     MarkAllViewportsDirty(
    01116       min(old_coord.left,   v->coord.left),
    01117       min(old_coord.top,    v->coord.top),
    01118       max(old_coord.right,  v->coord.right) + 1,
    01119       max(old_coord.bottom, v->coord.bottom) + 1
    01120     );
    01121   }
    01122 }
    01123
    01132 void MarkSingleVehicleDirty(const Vehicle *v)
    01133 {
    01134   MarkAllViewportsDirty(v->coord.left, v->coord.top, v->coord.right + 1, v->coord.bottom + 1);
    01135 }
    01136
    01141 GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
    01142 {
    01143   static const int8 _delta_coord[16] = {
    01144     -1,-1,-1, 0, 1, 1, 1, 0, /* x */
    01145     -1, 0, 1, 1, 1, 0,-1,-1, /* y */
    01146   };
    01147
    01148   int x = v->x_pos + _delta_coord[v->direction];
    01149   int y = v->y_pos + _delta_coord[v->direction + 8];
    01150
    01151   GetNewVehiclePosResult gp;
    01152   gp.x = x;
    01153   gp.y = y;
    01154   gp.old_tile = v->tile;
    01155   gp.new_tile = TileVirtXY(x, y);
    01156   return gp;
    01157 }
    01158
    01159 static const Direction _new_direction_table[] = {
    01160   DIR_N,  DIR_NW, DIR_W,
    01161   DIR_NE, DIR_SE, DIR_SW,
    01162   DIR_E,  DIR_SE, DIR_S
    01163 };
    01164
    01165 Direction GetDirectionTowards(const Vehicle *v, int x, int y)
    01166 {
    01167   int i = 0;
    01168
    01169   if (y >= v->y_pos) {
    01170     if (y != v->y_pos) i += 3;
    01171     i += 3;
    01172   }
    01173
    01174   if (x >= v->x_pos) {
    01175     if (x != v->x_pos) i++;
    01176     i++;
    01177   }
    01178
    01179   Direction dir = v->direction;
    01180
    01181   DirDiff dirdiff = DirDifference(_new_direction_table[i], dir);
    01182   if (dirdiff == DIRDIFF_SAME) return dir;
    01183   return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
    01184 }
    01185
    01195 VehicleEnterTileStatus VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
    01196 {
    01197   return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
    01198 }
    01199
    01200 FreeUnitIDGenerator::FreeUnitIDGenerator(VehicleType type, CompanyID owner) : cache(NULL), maxid(0), curid(0)
    01201 {
    01202   /* Find maximum */
    01203   const Vehicle *v;
    01204   FOR_ALL_VEHICLES(v) {
    01205     if (v->type == type && v->owner == owner) {
    01206       this->maxid = max<UnitID>(this->maxid, v->unitnumber);
    01207     }
    01208   }
    01209
    01210   if (this->maxid == 0) return;
    01211
    01212   /* Reserving 'maxid + 2' because we need:
    01213    * - space for the last item (with v->unitnumber == maxid)
    01214    * - one free slot working as loop terminator in FreeUnitIDGenerator::NextID() */
    01215   this->cache = CallocT<bool>(this->maxid + 2);
    01216
    01217   /* Fill the cache */
    01218   FOR_ALL_VEHICLES(v) {
    01219     if (v->type == type && v->owner == owner) {
    01220       this->cache[v->unitnumber] = true;
    01221     }
    01222   }
    01223 }
    01224
    01225 UnitID FreeUnitIDGenerator::NextID()
    01226 {
    01227   if (this->maxid <= this->curid) return ++this->curid;
    01228
    01229   while (this->cache[++this->curid]) { } // it will stop, we reserved more space than needed
    01230
    01231   return this->curid;
    01232 }
    01233
    01234 UnitID GetFreeUnitNumber(VehicleType type)
    01235 {
    01236   FreeUnitIDGenerator gen(type, _current_company);
    01237
    01238   return gen.NextID();
    01239 }
    01240
    01241
    01250 bool CanBuildVehicleInfrastructure(VehicleType type)
    01251 {
    01252   assert(IsCompanyBuildableVehicleType(type));
    01253
    01254   if (!Company::IsValidID(_local_company)) return false;
    01255   if (_settings_client.gui.always_build_infrastructure) return true;
    01256
    01257   UnitID max;
    01258   switch (type) {
    01259     case VEH_TRAIN:    max = _settings_game.vehicle.max_trains; break;
    01260     case VEH_ROAD:     max = _settings_game.vehicle.max_roadveh; break;
    01261     case VEH_SHIP:     max = _settings_game.vehicle.max_ships; break;
    01262     case VEH_AIRCRAFT: max = _settings_game.vehicle.max_aircraft; break;
    01263     default: NOT_REACHED();
    01264   }
    01265
    01266   /* We can build vehicle infrastructure when we may build the vehicle type */
    01267   if (max > 0) {
    01268     /* Can we actually build the vehicle type? */
    01269     const Engine *e;
    01270     FOR_ALL_ENGINES_OF_TYPE(e, type) {
    01271       if (HasBit(e->company_avail, _local_company)) return true;
    01272     }
    01273     return false;
    01274   }
    01275
    01276   /* We should be able to build infrastructure when we have the actual vehicle type */
    01277   const Vehicle *v;
    01278   FOR_ALL_VEHICLES(v) {
    01279     if (v->owner == _local_company && v->type == type) return true;
    01280   }
    01281
    01282   return false;
    01283 }
    01284
    01285
    01294 const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
    01295 {
    01296   const Company *c = Company::Get(company);
    01297   LiveryScheme scheme = LS_DEFAULT;
    01298   CargoID cargo_type = v == NULL ? (CargoID)CT_INVALID : v->cargo_type;
    01299
    01300   /* The default livery is always available for use, but its in_use flag determines
    01301    * whether any _other_ liveries are in use. */
    01302   if (c->livery[LS_DEFAULT].in_use && (_settings_client.gui.liveries == 2 || (_settings_client.gui.liveries == 1 && company == _local_company))) {
    01303     /* Determine the livery scheme to use */
    01304     const Engine *e = Engine::Get(engine_type);
    01305     switch (e->type) {
    01306       default: NOT_REACHED();
    01307       case VEH_TRAIN: {
    01308         if (v != NULL && parent_engine_type != INVALID_ENGINE && (UsesWagonOverride(v) || (Train::From(v)->IsArticulatedPart() && e->u.rail.railveh_type != RAILVEH_WAGON))) {
    01309           /* Wagonoverrides use the coloir scheme of the front engine.
    01310            * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */
    01311           engine_type = parent_engine_type;
    01312           e = Engine::Get(engine_type);
    01313           /* Note: Luckily cargo_type is not needed for engines */
    01314         }
    01315
    01316         if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01317         if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01318         if (e->u.rail.railveh_type == RAILVEH_WAGON) {
    01319           if (!CargoSpec::Get(cargo_type)->is_freight) {
    01320             if (parent_engine_type == INVALID_ENGINE) {
    01321               scheme = LS_PASSENGER_WAGON_STEAM;
    01322             } else {
    01323               switch (RailVehInfo(parent_engine_type)->engclass) {
    01324                 default: NOT_REACHED();
    01325                 case EC_STEAM:    scheme = LS_PASSENGER_WAGON_STEAM;    break;
    01326                 case EC_DIESEL:   scheme = LS_PASSENGER_WAGON_DIESEL;   break;
    01327                 case EC_ELECTRIC: scheme = LS_PASSENGER_WAGON_ELECTRIC; break;
    01328                 case EC_MONORAIL: scheme = LS_PASSENGER_WAGON_MONORAIL; break;
    01329                 case EC_MAGLEV:   scheme = LS_PASSENGER_WAGON_MAGLEV;   break;
    01330               }
    01331             }
    01332           } else {
    01333             scheme = LS_FREIGHT_WAGON;
    01334           }
    01335         } else {
    01336           bool is_mu = HasBit(e->info.misc_flags, EF_RAIL_IS_MU);
    01337
    01338           switch (e->u.rail.engclass) {
    01339             default: NOT_REACHED();
    01340             case EC_STEAM:    scheme = LS_STEAM; break;
    01341             case EC_DIESEL:   scheme = is_mu ? LS_DMU : LS_DIESEL;   break;
    01342             case EC_ELECTRIC: scheme = is_mu ? LS_EMU : LS_ELECTRIC; break;
    01343             case EC_MONORAIL: scheme = LS_MONORAIL; break;
    01344             case EC_MAGLEV:   scheme = LS_MAGLEV; break;
    01345           }
    01346         }
    01347         break;
    01348       }
    01349
    01350       case VEH_ROAD: {
    01351         /* Always use the livery of the front */
    01352         if (v != NULL && parent_engine_type != INVALID_ENGINE) {
    01353           engine_type = parent_engine_type;
    01354           e = Engine::Get(engine_type);
    01355           cargo_type = v->First()->cargo_type;
    01356         }
    01357         if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01358         if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01359
    01360         /* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */
    01361         if (HasBit(e->info.misc_flags, EF_ROAD_TRAM)) {
    01362           /* Tram */
    01363           scheme = IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
    01364         } else {
    01365           /* Bus or truck */
    01366           scheme = IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_BUS : LS_TRUCK;
    01367         }
    01368         break;
    01369       }
    01370
    01371       case VEH_SHIP: {
    01372         if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01373         if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01374         scheme = IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
    01375         break;
    01376       }
    01377
    01378       case VEH_AIRCRAFT: {
    01379         switch (e->u.air.subtype) {
    01380           case AIR_HELI: scheme = LS_HELICOPTER; break;
    01381           case AIR_CTOL: scheme = LS_SMALL_PLANE; break;
    01382           case AIR_CTOL | AIR_FAST: scheme = LS_LARGE_PLANE; break;
    01383         }
    01384         break;
    01385       }
    01386     }
    01387
    01388     /* Switch back to the default scheme if the resolved scheme is not in use */
    01389     if (!c->livery[scheme].in_use) scheme = LS_DEFAULT;
    01390   }
    01391
    01392   return &c->livery[scheme];
    01393 }
    01394
    01395
    01396 static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
    01397 {
    01398   PaletteID map = (v != NULL) ? v->colourmap : PAL_NONE;
    01399
    01400   /* Return cached value if any */
    01401   if (map != PAL_NONE) return map;
    01402
    01403   const Engine *e = Engine::Get(engine_type);
    01404
    01405   /* Check if we should use the colour map callback */
    01406   if (HasBit(e->info.callback_mask, CBM_VEHICLE_COLOUR_REMAP)) {
    01407     uint16 callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
    01408     /* A return value of 0xC000 is stated to "use the default two-colour
    01409      * maps" which happens to be the failure action too... */
    01410     if (callback != CALLBACK_FAILED && callback != 0xC000) {
    01411       map = GB(callback, 0, 14);
    01412       /* If bit 14 is set, then the company colours are applied to the
    01413        * map else it's returned as-is. */
    01414       if (!HasBit(callback, 14)) {
    01415         /* Update cache */
    01416         if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
    01417         return map;
    01418       }
    01419     }
    01420   }
    01421
    01422   bool twocc = HasBit(e->info.misc_flags, EF_USES_2CC);
    01423
    01424   if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
    01425
    01426   /* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
    01427   if (!Company::IsValidID(company)) return map;
    01428
    01429   const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v);
    01430
    01431   map += livery->colour1;
    01432   if (twocc) map += livery->colour2 * 16;
    01433
    01434   /* Update cache */
    01435   if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
    01436   return map;
    01437 }
    01438
    01439 PaletteID GetEnginePalette(EngineID engine_type, CompanyID company)
    01440 {
    01441   return GetEngineColourMap(engine_type, company, INVALID_ENGINE, NULL);
    01442 }
    01443
    01444 PaletteID GetVehiclePalette(const Vehicle *v)
    01445 {
    01446   if (v->type == VEH_TRAIN) {
    01447     return GetEngineColourMap(v->engine_type, v->owner, Train::From(v)->tcache.first_engine, v);
    01448   } else if (v->type == VEH_ROAD) {
    01449     return GetEngineColourMap(v->engine_type, v->owner, RoadVehicle::From(v)->rcache.first_engine, v);
    01450   }
    01451
    01452   return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
    01453 }
    01454
    01463 uint GetVehicleCapacity(const Vehicle *v, uint16 *mail_capacity)
    01464 {
    01465   if (mail_capacity != NULL) *mail_capacity = 0;
    01466   const Engine *e = Engine::Get(v->engine_type);
    01467
    01468   if (!e->CanCarryCargo()) return 0;
    01469
    01470   if (mail_capacity != NULL && e->type == VEH_AIRCRAFT && IsCargoInClass(v->cargo_type, CC_PASSENGERS)) {
    01471     *mail_capacity = GetVehicleProperty(v, PROP_AIRCRAFT_MAIL_CAPACITY, e->u.air.mail_capacity);
    01472   }
    01473   CargoID default_cargo = e->GetDefaultCargoType();
    01474
    01475   /* Check the refit capacity callback if we are not in the default configuration.
    01476    * Note: This might change to become more consistent/flexible/sane, esp. when default cargo is first refittable. */
    01477   if (HasBit(e->info.callback_mask, CBM_VEHICLE_REFIT_CAPACITY) &&
    01478       (default_cargo != v->cargo_type || v->cargo_subtype != 0)) {
    01479     uint16 callback = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, v->engine_type, v);
    01480     if (callback != CALLBACK_FAILED) return callback;
    01481   }
    01482
    01483   /* Get capacity according to property resp. CB */
    01484   uint capacity;
    01485   switch (e->type) {
    01486     case VEH_TRAIN:    capacity = GetVehicleProperty(v, PROP_TRAIN_CARGO_CAPACITY,        e->u.rail.capacity); break;
    01487     case VEH_ROAD:     capacity = GetVehicleProperty(v, PROP_ROADVEH_CARGO_CAPACITY,      e->u.road.capacity); break;
    01488     case VEH_SHIP:     capacity = GetVehicleProperty(v, PROP_SHIP_CARGO_CAPACITY,         e->u.ship.capacity); break;
    01489     case VEH_AIRCRAFT: capacity = GetVehicleProperty(v, PROP_AIRCRAFT_PASSENGER_CAPACITY, e->u.air.passenger_capacity); break;
    01490     default: NOT_REACHED();
    01491   }
    01492
    01493   /* Apply multipliers depending on cargo- and vehicletype.
    01494    * Note: This might change to become more consistent/flexible. */
    01495   if (e->type != VEH_SHIP) {
    01496     if (e->type == VEH_AIRCRAFT) {
    01497       if (!IsCargoInClass(v->cargo_type, CC_PASSENGERS)) {
    01498         capacity += GetVehicleProperty(v, PROP_AIRCRAFT_MAIL_CAPACITY, e->u.air.mail_capacity);
    01499       }
    01500       if (v->cargo_type == CT_MAIL) return capacity;
    01501     } else {
    01502       switch (default_cargo) {
    01503         case CT_PASSENGERS: break;
    01504         case CT_MAIL:
    01505         case CT_GOODS: capacity *= 2; break;
    01506         default:       capacity *= 4; break;
    01507       }
    01508     }
    01509     switch (v->cargo_type) {
    01510       case CT_PASSENGERS: break;
    01511       case CT_MAIL:
    01512       case CT_GOODS: capacity /= 2; break;
    01513       default:       capacity /= 4; break;
    01514     }
    01515   }
    01516
    01517   return capacity;
    01518 }
    01519
    01520
    01521 void Vehicle::BeginLoading()
    01522 {
    01523   assert(IsTileType(tile, MP_STATION) || type == VEH_SHIP);
    01524
    01525   if (this->current_order.IsType(OT_GOTO_STATION) &&
    01526       this->current_order.GetDestination() == this->last_station_visited) {
    01527     current_order.MakeLoading(true);
    01528     UpdateVehicleTimetable(this, true);
    01529
    01530     /* Furthermore add the Non Stop flag to mark that this station
    01531      * is the actual destination of the vehicle, which is (for example)
    01532      * necessary to be known for HandleTrainLoading to determine
    01533      * whether the train is lost or not; not marking a train lost
    01534      * that arrives at random stations is bad. */
    01535     this->current_order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
    01536
    01537   } else {
    01538     current_order.MakeLoading(false);
    01539   }
    01540
    01541   Station::Get(this->last_station_visited)->loading_vehicles.push_back(this);
    01542
    01543   PrepareUnload(this);
    01544
    01545   SetWindowDirty(GetWindowClassForVehicleType(this->type), this->owner);
    01546   SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    01547   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
    01548   SetWindowDirty(WC_STATION_VIEW, this->last_station_visited);
    01549
    01550   Station::Get(this->last_station_visited)->MarkTilesDirty(true);
    01551   this->cur_speed = 0;
    01552   this->MarkDirty();
    01553 }
    01554
    01555 void Vehicle::LeaveStation()
    01556 {
    01557   assert(current_order.IsType(OT_LOADING));
    01558
    01559   delete this->cargo_payment;
    01560
    01561   /* Only update the timetable if the vehicle was supposed to stop here. */
    01562   if (current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE) UpdateVehicleTimetable(this, false);
    01563
    01564   current_order.MakeLeaveStation();
    01565   Station *st = Station::Get(this->last_station_visited);
    01566   st->loading_vehicles.remove(this);
    01567
    01568   HideFillingPercent(&this->fill_percent_te_id);
    01569
    01570   if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) {
    01571     /* Trigger station animation (trains only) */
    01572     if (IsTileType(this->tile, MP_STATION)) StationAnimationTrigger(st, this->tile, STAT_ANIM_TRAIN_DEPARTS);
    01573
    01574     /* Try to reserve a path when leaving the station as we
    01575      * might not be marked as wanting a reservation, e.g.
    01576      * when an overlength train gets turned around in a station. */
    01577     if (UpdateSignalsOnSegment(this->tile, TrackdirToExitdir(this->GetVehicleTrackdir()), this->owner) == SIGSEG_PBS || _settings_game.pf.reserve_paths) {
    01578       TryPathReserve(Train::From(this), true, true);
    01579     }
    01580   }
    01581 }
    01582
    01583
    01584 void Vehicle::HandleLoading(bool mode)
    01585 {
    01586   switch (this->current_order.GetType()) {
    01587     case OT_LOADING: {
    01588       uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0);
    01589
    01590       /* Not the first call for this tick, or still loading */
    01591       if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) ||
    01592           (_settings_game.order.timetabling && this->current_order_time < wait_time)) return;
    01593
    01594       this->PlayLeaveStationSound();
    01595
    01596       bool at_destination_station = this->current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE;
    01597       this->LeaveStation();
    01598
    01599       /* If this was not the final order, don't remove it from the list. */
    01600       if (!at_destination_station) return;
    01601       break;
    01602     }
    01603
    01604     case OT_DUMMY: break;
    01605
    01606     default: return;
    01607   }
    01608
    01609   this->IncrementOrderIndex();
    01610 }
    01611
    01612 CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command)
    01613 {
    01614   if (!CheckOwnership(this->owner)) return CMD_ERROR;
    01615   if (this->vehstatus & VS_CRASHED) return CMD_ERROR;
    01616   if (this->IsStoppedInDepot()) return CMD_ERROR;
    01617
    01618   if (this->current_order.IsType(OT_GOTO_DEPOT)) {
    01619     bool halt_in_depot = (this->current_order.GetDepotActionType() & ODATFB_HALT) != 0;
    01620     if (!!(command & DEPOT_SERVICE) == halt_in_depot) {
    01621       /* We called with a different DEPOT_SERVICE setting.
    01622        * Now we change the setting to apply the new one and let the vehicle head for the same depot.
    01623        * Note: the if is (true for requesting service == true for ordered to stop in depot)          */
    01624       if (flags & DC_EXEC) {
    01625         this->current_order.SetDepotOrderType(ODTF_MANUAL);
    01626         this->current_order.SetDepotActionType(halt_in_depot ? ODATF_SERVICE_ONLY : ODATFB_HALT);
    01627         SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    01628       }
    01629       return CommandCost();
    01630     }
    01631
    01632     if (command & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
    01633     if (flags & DC_EXEC) {
    01634       /* If the orders to 'goto depot' are in the orders list (forced servicing),
    01635        * then skip to the next order; effectively cancelling this forced service */
    01636       if (this->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) this->IncrementOrderIndex();
    01637
    01638       this->current_order.MakeDummy();
    01639       SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    01640     }
    01641     return CommandCost();
    01642   }
    01643
    01644   TileIndex location;
    01645   DestinationID destination;
    01646   bool reverse;
    01647   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};
    01648   if (!this->FindClosestDepot(&location, &destination, &reverse)) return_cmd_error(no_depot[this->type]);
    01649
    01650   if (flags & DC_EXEC) {
    01651     if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
    01652
    01653     this->dest_tile = location;
    01654     this->current_order.MakeGoToDepot(destination, ODTF_MANUAL);
    01655     if (!(command & DEPOT_SERVICE)) this->current_order.SetDepotActionType(ODATFB_HALT);
    01656     SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    01657
    01658     /* If there is no depot in front, reverse automatically (trains only) */
    01659     if (this->type == VEH_TRAIN && reverse) DoCommand(this->tile, this->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
    01660
    01661     if (this->type == VEH_AIRCRAFT) {
    01662       Aircraft *a = Aircraft::From(this);
    01663       if (a->state == FLYING && a->targetairport != destination) {
    01664         /* The aircraft is now heading for a different hangar than the next in the orders */
    01665         extern void AircraftNextAirportPos_and_Order(Aircraft *a);
    01666         AircraftNextAirportPos_and_Order(a);
    01667       }
    01668     }
    01669   }
    01670
    01671   return CommandCost();
    01672
    01673 }
    01674
    01675 void Vehicle::SetNext(Vehicle *next)
    01676 {
    01677   assert(this != next);
    01678
    01679   if (this->next != NULL) {
    01680     /* We had an old next vehicle. Update the first and previous pointers */
    01681     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
    01682       v->first = this->next;
    01683     }
    01684     this->next->previous = NULL;
    01685   }
    01686
    01687   this->next = next;
    01688
    01689   if (this->next != NULL) {
    01690     /* A new next vehicle. Update the first and previous pointers */
    01691     if (this->next->previous != NULL) this->next->previous->next = NULL;
    01692     this->next->previous = this;
    01693     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
    01694       v->first = this->first;
    01695     }
    01696   }
    01697 }
    01698
    01699 void Vehicle::AddToShared(Vehicle *shared_chain)
    01700 {
    01701   assert(this->previous_shared == NULL && this->next_shared == NULL);
    01702
    01703   if (!shared_chain->orders.list) {
    01704     assert(shared_chain->previous_shared == NULL);
    01705     assert(shared_chain->next_shared == NULL);
    01706     this->orders.list = shared_chain->orders.list = new OrderList(NULL, shared_chain);
    01707   }
    01708
    01709   this->next_shared     = shared_chain->next_shared;
    01710   this->previous_shared = shared_chain;
    01711
    01712   shared_chain->next_shared = this;
    01713
    01714   if (this->next_shared != NULL) this->next_shared->previous_shared = this;
    01715
    01716   shared_chain->orders.list->AddVehicle(this);
    01717 }
    01718
    01719 void Vehicle::RemoveFromShared()
    01720 {
    01721   /* Remember if we were first and the old window number before RemoveVehicle()
    01722    * as this changes first if needed. */
    01723   bool were_first = (this->FirstShared() == this);
    01724   uint32 old_window_number = (this->FirstShared()->index << 16) | (this->type << 11) | VLW_SHARED_ORDERS | this->owner;
    01725
    01726   this->orders.list->RemoveVehicle(this);
    01727
    01728   if (!were_first) {
    01729     /* We are not the first shared one, so only relink our previous one. */
    01730     this->previous_shared->next_shared = this->NextShared();
    01731   }
    01732
    01733   if (this->next_shared != NULL) this->next_shared->previous_shared = this->previous_shared;
    01734
    01735
    01736   if (this->orders.list->GetNumVehicles() == 1) {
    01737     /* When there is only one vehicle, remove the shared order list window. */
    01738     DeleteWindowById(GetWindowClassForVehicleType(this->type), old_window_number);
    01739     InvalidateVehicleOrder(this->FirstShared(), 0);
    01740   } else if (were_first) {
    01741     /* If we were the first one, update to the new first one.
    01742      * Note: FirstShared() is already the new first */
    01743     InvalidateWindowData(GetWindowClassForVehicleType(this->type), old_window_number, (this->FirstShared()->index << 16) | (1 << 15));
    01744   }
    01745
    01746   this->next_shared     = NULL;
    01747   this->previous_shared = NULL;
    01748 }
    01749
    01750 void StopAllVehicles()
    01751 {
    01752   Vehicle *v;
    01753   FOR_ALL_VEHICLES(v) {
    01754     /* Code ripped from CmdStartStopTrain. Can't call it, because of
    01755      * ownership problems, so we'll duplicate some code, for now */
    01756     v->vehstatus |= VS_STOPPED;
    01757     v->MarkDirty();
    01758     SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
    01759     SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
    01760   }
    01761 }
    01762
    01763 void VehiclesYearlyLoop()
    01764 {
    01765   Vehicle *v;
    01766   FOR_ALL_VEHICLES(v) {
    01767     if (v->IsPrimaryVehicle()) {
    01768       /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
    01769       Money profit = v->GetDisplayProfitThisYear();
    01770       if (v->age >= 730 && profit < 0) {
    01771         if (_settings_client.gui.vehicle_income_warn && v->owner == _local_company) {
    01772           SetDParam(0, v->index);
    01773           SetDParam(1, profit);
    01774           AddVehicleNewsItem(
    01775             STR_NEWS_VEHICLE_IS_UNPROFITABLE,
    01776             NS_ADVICE,
    01777             v->index
    01778           );
    01779         }
    01780         AI::NewEvent(v->owner, new AIEventVehicleUnprofitable(v->index));
    01781       }
    01782
    01783       v->profit_last_year = v->profit_this_year;
    01784       v->profit_this_year = 0;
    01785       SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    01786     }
    01787   }
    01788 }
    01789
    01790
    01800 bool CanVehicleUseStation(EngineID engine_type, const Station *st)
    01801 {
    01802   const Engine *e = Engine::GetIfValid(engine_type);
    01803   assert(e != NULL);
    01804
    01805   switch (e->type) {
    01806     case VEH_TRAIN:
    01807       return (st->facilities & FACIL_TRAIN) != 0;
    01808
    01809     case VEH_ROAD:
    01810       /* For road vehicles we need the vehicle to know whether it can actually
    01811        * use the station, but if it doesn't have facilities for RVs it is
    01812        * certainly not possible that the station can be used. */
    01813       return (st->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP)) != 0;
    01814
    01815     case VEH_SHIP:
    01816       return (st->facilities & FACIL_DOCK) != 0;
    01817
    01818     case VEH_AIRCRAFT:
    01819       return (st->facilities & FACIL_AIRPORT) != 0 &&
    01820           (st->Airport()->flags & (e->u.air.subtype & AIR_CTOL ? AirportFTAClass::AIRPLANES : AirportFTAClass::HELICOPTERS)) != 0;
    01821
    01822     default:
    01823       return false;
    01824   }
    01825 }
    01826
    01833 bool CanVehicleUseStation(const Vehicle *v, const Station *st)
    01834 {
    01835   if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != NULL;
    01836
    01837   return CanVehicleUseStation(v->engine_type, st);
    01838 }