# vehicle.cpp

Go to the documentation of this file.

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