# vehicle.cpp

Go to the documentation of this file.

    00001 /* $Id: vehicle.cpp 20608 2010-08-24 00:03:26Z 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
    00539 void CountCompanyVehicles(CompanyID cid, uint counts[4])
    00540 {
    00541   for (uint i = 0; i < 4; i++) counts[i] = 0;
    00542
    00543   const Vehicle *v;
    00544   FOR_ALL_VEHICLES(v) {
    00545     if (v->owner == cid && v->IsPrimaryVehicle()) counts[v->type]++;
    00546   }
    00547 }
    00548
    00552 bool Vehicle::IsEngineCountable() const
    00553 {
    00554   switch (this->type) {
    00555     case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft(); // don't count plane shadows and helicopter rotors
    00556     case VEH_TRAIN:
    00557       return !Train::From(this)->IsArticulatedPart() && // tenders and other articulated parts
    00558           !Train::From(this)->IsRearDualheaded(); // rear parts of multiheaded engines
    00559     case VEH_ROAD: return RoadVehicle::From(this)->IsRoadVehFront();
    00560     case VEH_SHIP: return true;
    00561     default: return false; // Only count company buildable vehicles
    00562   }
    00563 }
    00564
    00565 void Vehicle::PreDestructor()
    00566 {
    00567   if (CleaningPool()) return;
    00568
    00569   if (Station::IsValidID(this->last_station_visited)) {
    00570     Station::Get(this->last_station_visited)->loading_vehicles.remove(this);
    00571
    00572     HideFillingPercent(&this->fill_percent_te_id);
    00573
    00574     delete this->cargo_payment;
    00575   }
    00576
    00577   if (this->IsEngineCountable()) {
    00578     Company::Get(this->owner)->num_engines[this->engine_type]--;
    00579     if (this->owner == _local_company) InvalidateAutoreplaceWindow(this->engine_type, this->group_id);
    00580
    00581     DeleteGroupHighlightOfVehicle(this);
    00582     if (Group::IsValidID(this->group_id)) Group::Get(this->group_id)->num_engines[this->engine_type]--;
    00583     if (this->IsPrimaryVehicle()) DecreaseGroupNumVehicle(this->group_id);
    00584   }
    00585
    00586   if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) {
    00587     Aircraft *a = Aircraft::From(this);
    00588     Station *st = GetTargetAirportIfValid(a);
    00589     if (st != NULL) {
    00590       const AirportFTA *layout = st->Airport()->layout;
    00591       CLRBITS(st->airport_flags, layout[a->previous_pos].block | layout[a->pos].block);
    00592     }
    00593   }
    00594
    00595
    00596   if (this->type == VEH_ROAD && this->IsPrimaryVehicle()) {
    00597     RoadVehicle *v = RoadVehicle::From(this);
    00598     if (!(v->vehstatus & VS_CRASHED) && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
    00599       /* Leave the drive through roadstop, when you have not already left it. */
    00600       RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
    00601     }
    00602   }
    00603
    00604   if (this->Previous() == NULL) {
    00605     InvalidateWindowData(WC_VEHICLE_DEPOT, this->tile);
    00606   }
    00607
    00608   if (this->IsPrimaryVehicle()) {
    00609     DeleteWindowById(WC_VEHICLE_VIEW, this->index);
    00610     DeleteWindowById(WC_VEHICLE_ORDERS, this->index);
    00611     DeleteWindowById(WC_VEHICLE_REFIT, this->index);
    00612     DeleteWindowById(WC_VEHICLE_DETAILS, this->index);
    00613     DeleteWindowById(WC_VEHICLE_TIMETABLE, this->index);
    00614     SetWindowDirty(WC_COMPANY, this->owner);
    00615   }
    00616   InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
    00617
    00618   this->cargo.Truncate(0);
    00619   DeleteVehicleOrders(this);
    00620   DeleteDepotHighlightOfVehicle(this);
    00621
    00622   extern void StopGlobalFollowVehicle(const Vehicle *v);
    00623   StopGlobalFollowVehicle(this);
    00624
    00625   ReleaseDisastersTargetingVehicle(this->index);
    00626 }
    00627
    00628 Vehicle::~Vehicle()
    00629 {
    00630   free(this->name);
    00631
    00632   if (CleaningPool()) return;
    00633
    00634   /* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles,
    00635    * it may happen that vehicle chain is deleted when visible */
    00636   if (!(this->vehstatus & VS_HIDDEN)) MarkSingleVehicleDirty(this);
    00637
    00638   Vehicle *v = this->Next();
    00639   this->SetNext(NULL);
    00640
    00641   delete v;
    00642
    00643   UpdateVehiclePosHash(this, INVALID_COORD, 0);
    00644   DeleteVehicleNews(this->index, INVALID_STRING_ID);
    00645 }
    00646
    00650 void VehicleEnteredDepotThisTick(Vehicle *v)
    00651 {
    00652   /* Vehicle should stop in the depot if it was in 'stopping' state */
    00653   _vehicles_to_autoreplace[v] = !(v->vehstatus & VS_STOPPED);
    00654
    00655   /* We ALWAYS set the stopped state. Even when the vehicle does not plan on
    00656    * stopping in the depot, so we stop it to ensure that it will not reserve
    00657    * the path out of the depot before we might autoreplace it to a different
    00658    * engine. The new engine would not own the reserved path we store that we
    00659    * stopped the vehicle, so autoreplace can start it again */
    00660   v->vehstatus |= VS_STOPPED;
    00661 }
    00662
    00668 static void RunVehicleDayProc()
    00669 {
    00670   if (_game_mode != GM_NORMAL) return;
    00671
    00672   /* Run the day_proc for every DAY_TICKS vehicle starting at _date_fract. */
    00673   for (size_t i = _date_fract; i < Vehicle::GetPoolSize(); i += DAY_TICKS) {
    00674     Vehicle *v = Vehicle::Get(i);
    00675     if (v == NULL) continue;
    00676
    00677     /* Call the 32-day callback if needed */
    00678     if ((v->day_counter & 0x1F) == 0) {
    00679       uint16 callback = GetVehicleCallback(CBID_VEHICLE_32DAY_CALLBACK, 0, 0, v->engine_type, v);
    00680       if (callback != CALLBACK_FAILED) {
    00681         if (HasBit(callback, 0)) TriggerVehicle(v, VEHICLE_TRIGGER_CALLBACK_32); // Trigger vehicle trigger 10
    00682         if (HasBit(callback, 1)) v->colourmap = PAL_NONE;
    00683       }
    00684     }
    00685
    00686     /* This is called once per day for each vehicle, but not in the first tick of the day */
    00687     v->OnNewDay();
    00688   }
    00689 }
    00690
    00691 void CallVehicleTicks()
    00692 {
    00693   _vehicles_to_autoreplace.Clear();
    00694
    00695   _age_cargo_skip_counter = (_age_cargo_skip_counter == 0) ? 184 : (_age_cargo_skip_counter - 1);
    00696
    00697   RunVehicleDayProc();
    00698
    00699   Station *st;
    00700   FOR_ALL_STATIONS(st) LoadUnloadStation(st);
    00701
    00702   Vehicle *v;
    00703   FOR_ALL_VEHICLES(v) {
    00704     /* Vehicle could be deleted in this tick */
    00705     if (!v->Tick()) {
    00706       assert(Vehicle::Get(vehicle_index) == NULL);
    00707       continue;
    00708     }
    00709
    00710     assert(Vehicle::Get(vehicle_index) == v);
    00711
    00712     switch (v->type) {
    00713       default: break;
    00714
    00715       case VEH_TRAIN:
    00716       case VEH_ROAD:
    00717       case VEH_AIRCRAFT:
    00718       case VEH_SHIP:
    00719         if (_age_cargo_skip_counter == 0) v->cargo.AgeCargo();
    00720
    00721         if (v->type == VEH_TRAIN && Train::From(v)->IsWagon()) continue;
    00722         if (v->type == VEH_AIRCRAFT && v->subtype != AIR_HELICOPTER) continue;
    00723         if (v->type == VEH_ROAD && !RoadVehicle::From(v)->IsRoadVehFront()) continue;
    00724
    00725         v->motion_counter += v->cur_speed;
    00726         /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
    00727         if (GB(v->motion_counter, 0, 8) < v->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
    00728
    00729         /* Play an alterate running sound every 16 ticks */
    00730         if (GB(v->tick_counter, 0, 4) == 0) PlayVehicleSound(v, v->cur_speed > 0 ? VSE_RUNNING_16 : VSE_STOPPED_16);
    00731     }
    00732   }
    00733
    00734   for (AutoreplaceMap::iterator it = _vehicles_to_autoreplace.Begin(); it != _vehicles_to_autoreplace.End(); it++) {
    00735     v = it->first;
    00736     /* Autoreplace needs the current company set as the vehicle owner */
    00737     _current_company = v->owner;
    00738
    00739     /* Start vehicle if we stopped them in VehicleEnteredDepotThisTick()
    00740      * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that
    00741      * they are already leaving the depot again before being replaced. */
    00742     if (it->second) v->vehstatus &= ~VS_STOPPED;
    00743
    00744     /* Store the position of the effect as the vehicle pointer will become invalid later */
    00745     int x = v->x_pos;
    00746     int y = v->y_pos;
    00747     int z = v->z_pos;
    00748
    00749     const Company *c = Company::Get(_current_company);
    00750     SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, (Money)c->settings.engine_renew_money));
    00751     CommandCost res = DoCommand(0, v->index, 0, DC_EXEC, CMD_AUTOREPLACE_VEHICLE);
    00752     SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, -(Money)c->settings.engine_renew_money));
    00753
    00754     if (!IsLocalCompany()) continue;
    00755
    00756     if (res.Succeeded()) {
    00757       ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
    00758       continue;
    00759     }
    00760
    00761     StringID error_message = res.GetErrorMessage();
    00762     if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message == INVALID_STRING_ID) continue;
    00763
    00764     if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT;
    00765
    00766     StringID message;
    00767     if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
    00768       message = error_message;
    00769     } else {
    00770       message = STR_NEWS_VEHICLE_AUTORENEW_FAILED;
    00771     }
    00772
    00773     SetDParam(0, v->index);
    00774     SetDParam(1, error_message);
    00775     AddVehicleNewsItem(message, NS_ADVICE, v->index);
    00776   }
    00777
    00778   _current_company = OWNER_NONE;
    00779 }
    00780
    00781 static void DoDrawVehicle(const Vehicle *v)
    00782 {
    00783   SpriteID image = v->cur_image;
    00784   PaletteID pal = PAL_NONE;
    00785
    00786   if (v->vehstatus & VS_DEFPAL) pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
    00787
    00788   AddSortableSpriteToDraw(image, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
    00789     v->x_extent, v->y_extent, v->z_extent, v->z_pos, (v->vehstatus & VS_SHADOW) != 0);
    00790 }
    00791
    00792 void ViewportAddVehicles(DrawPixelInfo *dpi)
    00793 {
    00794   /* The bounding rectangle */
    00795   const int l = dpi->left;
    00796   const int r = dpi->left + dpi->width;
    00797   const int t = dpi->top;
    00798   const int b = dpi->top + dpi->height;
    00799
    00800   /* The hash area to scan */
    00801   int xl, xu, yl, yu;
    00802
    00803   if (dpi->width + 70 < (1 << (7 + 6))) {
    00804     xl = GB(l - 70, 7, 6);
    00805     xu = GB(r,      7, 6);
    00806   } else {
    00807     /* scan whole hash row */
    00808     xl = 0;
    00809     xu = 0x3F;
    00810   }
    00811
    00812   if (dpi->height + 70 < (1 << (6 + 6))) {
    00813     yl = GB(t - 70, 6, 6) << 6;
    00814     yu = GB(b,      6, 6) << 6;
    00815   } else {
    00816     /* scan whole column */
    00817     yl = 0;
    00818     yu = 0x3F << 6;
    00819   }
    00820
    00821   for (int y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
    00822     for (int x = xl;; x = (x + 1) & 0x3F) {
    00823       const Vehicle *v = _vehicle_position_hash[x + y]; // already masked & 0xFFF
    00824
    00825       while (v != NULL) {
    00826         if (!(v->vehstatus & VS_HIDDEN) &&
    00827             l <= v->coord.right &&
    00828             t <= v->coord.bottom &&
    00829             r >= v->coord.left &&
    00830             b >= v->coord.top) {
    00831           DoDrawVehicle(v);
    00832         }
    00833         v = v->next_hash;
    00834       }
    00835
    00836       if (x == xu) break;
    00837     }
    00838
    00839     if (y == yu) break;
    00840   }
    00841 }
    00842
    00843 Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y)
    00844 {
    00845   Vehicle *found = NULL, *v;
    00846   uint dist, best_dist = UINT_MAX;
    00847
    00848   if ((uint)(x -= vp->left) >= (uint)vp->width || (uint)(y -= vp->top) >= (uint)vp->height) return NULL;
    00849
    00850   x = ScaleByZoom(x, vp->zoom) + vp->virtual_left;
    00851   y = ScaleByZoom(y, vp->zoom) + vp->virtual_top;
    00852
    00853   FOR_ALL_VEHICLES(v) {
    00854     if ((v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0 &&
    00855         x >= v->coord.left && x <= v->coord.right &&
    00856         y >= v->coord.top && y <= v->coord.bottom) {
    00857
    00858       dist = max(
    00859         abs(((v->coord.left + v->coord.right) >> 1) - x),
    00860         abs(((v->coord.top + v->coord.bottom) >> 1) - y)
    00861       );
    00862
    00863       if (dist < best_dist) {
    00864         found = v;
    00865         best_dist = dist;
    00866       }
    00867     }
    00868   }
    00869
    00870   return found;
    00871 }
    00872
    00873 void DecreaseVehicleValue(Vehicle *v)
    00874 {
    00875   v->value -= v->value >> 8;
    00876   SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    00877 }
    00878
    00879 static const byte _breakdown_chance[64] = {
    00880     3,   3,   3,   3,   3,   3,   3,   3,
    00881     4,   4,   5,   5,   6,   6,   7,   7,
    00882     8,   8,   9,   9,  10,  10,  11,  11,
    00883    12,  13,  13,  13,  13,  14,  15,  16,
    00884    17,  19,  21,  25,  28,  31,  34,  37,
    00885    40,  44,  48,  52,  56,  60,  64,  68,
    00886    72,  80,  90, 100, 110, 120, 130, 140,
    00887   150, 170, 190, 210, 230, 250, 250, 250,
    00888 };
    00889
    00890 void CheckVehicleBreakdown(Vehicle *v)
    00891 {
    00892   int rel, rel_old;
    00893
    00894   /* decrease reliability */
    00895   v->reliability = rel = max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
    00896   if ((rel_old >> 8) != (rel >> 8)) SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    00897
    00898   if (v->breakdown_ctr != 0 || (v->vehstatus & VS_STOPPED) ||
    00899       _settings_game.difficulty.vehicle_breakdowns < 1 ||
    00900       v->cur_speed < 5 || _game_mode == GM_MENU) {
    00901     return;
    00902   }
    00903
    00904   uint32 r = Random();
    00905
    00906   /* increase chance of failure */
    00907   int chance = v->breakdown_chance + 1;
    00908   if (Chance16I(1, 25, r)) chance += 25;
    00909   v->breakdown_chance = min(255, chance);
    00910
    00911   /* calculate reliability value to use in comparison */
    00912   rel = v->reliability;
    00913   if (v->type == VEH_SHIP) rel += 0x6666;
    00914
    00915   /* reduced breakdowns? */
    00916   if (_settings_game.difficulty.vehicle_breakdowns == 1) rel += 0x6666;
    00917
    00918   /* check if to break down */
    00919   if (_breakdown_chance[(uint)min(rel, 0xffff) >> 10] <= v->breakdown_chance) {
    00920     v->breakdown_ctr    = GB(r, 16, 6) + 0x3F;
    00921     v->breakdown_delay  = GB(r, 24, 7) + 0x80;
    00922     v->breakdown_chance = 0;
    00923   }
    00924 }
    00925
    00926 void AgeVehicle(Vehicle *v)
    00927 {
    00928   if (v->age < 65535) v->age++;
    00929
    00930   int age = v->age - v->max_age;
    00931   if (age == DAYS_IN_LEAP_YEAR * 0 || age == DAYS_IN_LEAP_YEAR * 1 ||
    00932       age == DAYS_IN_LEAP_YEAR * 2 || age == DAYS_IN_LEAP_YEAR * 3 || age == DAYS_IN_LEAP_YEAR * 4) {
    00933     v->reliability_spd_dec <<= 1;
    00934   }
    00935
    00936   SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    00937
    00938   /* Don't warn about non-primary or not ours vehicles or vehicles that are crashed */
    00939   if (v->Previous() != NULL || v->owner != _local_company || (v->vehstatus & VS_CRASHED) != 0) return;
    00940
    00941   /* Don't warn if a renew is active */
    00942   if (Company::Get(v->owner)->settings.engine_renew && Engine::Get(v->engine_type)->company_avail != 0) return;
    00943
    00944   StringID str;
    00945   if (age == -DAYS_IN_LEAP_YEAR) {
    00946     str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
    00947   } else if (age == 0) {
    00948     str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
    00949   } else if (age > 0 && (age % DAYS_IN_LEAP_YEAR) == 0) {
    00950     str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
    00951   } else {
    00952     return;
    00953   }
    00954
    00955   SetDParam(0, v->index);
    00956   AddVehicleNewsItem(str, NS_ADVICE, v->index);
    00957 }
    00958
    00965 uint8 CalcPercentVehicleFilled(const Vehicle *v, StringID *colour)
    00966 {
    00967   int count = 0;
    00968   int max = 0;
    00969   int cars = 0;
    00970   int unloading = 0;
    00971   bool loading = false;
    00972
    00973   const Vehicle *u = v;
    00974   /* The station may be NULL when the (colour) string does not need to be set. */
    00975   const Station *st = Station::GetIfValid(v->last_station_visited);
    00976   assert(colour == NULL || st != NULL);
    00977
    00978   /* Count up max and used */
    00979   for (; v != NULL; v = v->Next()) {
    00980     count += v->cargo.Count();
    00981     max += v->cargo_cap;
    00982     if (v->cargo_cap != 0 && colour != NULL) {
    00983       unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0;
    00984       loading |= !(u->current_order.GetLoadType() & OLFB_NO_LOAD) && st->goods[v->cargo_type].days_since_pickup != 255;
    00985       cars++;
    00986     }
    00987   }
    00988
    00989   if (colour != NULL) {
    00990     if (unloading == 0 && loading) {
    00991       *colour = STR_PERCENT_UP;
    00992     } else if (cars == unloading || !loading) {
    00993       *colour = STR_PERCENT_DOWN;
    00994     } else {
    00995       *colour = STR_PERCENT_UP_DOWN;
    00996     }
    00997   }
    00998
    00999   /* Train without capacity */
    01000   if (max == 0) return 100;
    01001
    01002   /* Return the percentage */
    01003   return (count * 100) / max;
    01004 }
    01005
    01006 void VehicleEnterDepot(Vehicle *v)
    01007 {
    01008   /* Always work with the front of the vehicle */
    01009   assert(v == v->First());
    01010
    01011   switch (v->type) {
    01012     case VEH_TRAIN: {
    01013       Train *t = Train::From(v);
    01014       SetWindowClassesDirty(WC_TRAINS_LIST);
    01015       /* Clear path reservation */
    01016       SetDepotReservation(t->tile, false);
    01017       if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(t->tile);
    01018
    01019       UpdateSignalsOnSegment(t->tile, INVALID_DIAGDIR, t->owner);
    01020       t->wait_counter = 0;
    01021       t->force_proceed = 0;
    01022       ClrBit(t->flags, VRF_TOGGLE_REVERSE);
    01023       t->ConsistChanged(true);
    01024       break;
    01025     }
    01026
    01027     case VEH_ROAD:
    01028       SetWindowClassesDirty(WC_ROADVEH_LIST);
    01029       break;
    01030
    01031     case VEH_SHIP: {
    01032       SetWindowClassesDirty(WC_SHIPS_LIST);
    01033       Ship *ship = Ship::From(v);
    01034       ship->state = TRACK_BIT_DEPOT;
    01035       ship->UpdateViewport(true, true);
    01036       SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
    01037       break;
    01038     }
    01039
    01040     case VEH_AIRCRAFT:
    01041       SetWindowClassesDirty(WC_AIRCRAFT_LIST);
    01042       HandleAircraftEnterHangar(Aircraft::From(v));
    01043       break;
    01044     default: NOT_REACHED();
    01045   }
    01046   SetWindowDirty(WC_VEHICLE_VIEW, v->index);
    01047
    01048   if (v->type != VEH_TRAIN) {
    01049     /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
    01050      * 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 */
    01051     InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
    01052   }
    01053   SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
    01054
    01055   v->vehstatus |= VS_HIDDEN;
    01056   v->cur_speed = 0;
    01057
    01058   VehicleServiceInDepot(v);
    01059
    01060   TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
    01061
    01062   if (v->current_order.IsType(OT_GOTO_DEPOT)) {
    01063     SetWindowDirty(WC_VEHICLE_VIEW, v->index);
    01064
    01065     const Order *real_order = v->GetOrder(v->cur_order_index);
    01066     Order t = v->current_order;
    01067     v->current_order.MakeDummy();
    01068
    01069     /* Test whether we are heading for this depot. If not, do nothing.
    01070      * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
    01071     if ((t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) &&
    01072         real_order != NULL && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) &&
    01073         (v->type == VEH_AIRCRAFT ? t.GetDestination() != GetStationIndex(v->tile) : v->dest_tile != v->tile)) {
    01074       /* We are heading for another depot, keep driving. */
    01075       return;
    01076     }
    01077
    01078     if (t.IsRefit()) {
    01079       _current_company = v->owner;
    01080       CommandCost cost = DoCommand(v->tile, v->index, t.GetRefitCargo() | t.GetRefitSubtype() << 8, DC_EXEC, GetCmdRefitVeh(v));
    01081
    01082       if (cost.Failed()) {
    01083         _vehicles_to_autoreplace[v] = false;
    01084         if (v->owner == _local_company) {
    01085           /* Notify the user that we stopped the vehicle */
    01086           SetDParam(0, v->index);
    01087           AddVehicleNewsItem(STR_NEWS_ORDER_REFIT_FAILED, NS_ADVICE, v->index);
    01088         }
    01089       } else if (cost.GetCost() != 0) {
    01090         v->profit_this_year -= cost.GetCost() << 8;
    01091         if (v->owner == _local_company) {
    01092           ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
    01093         }
    01094       }
    01095     }
    01096
    01097     if (t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
    01098       /* Part of orders */
    01099       UpdateVehicleTimetable(v, true);
    01100       v->IncrementOrderIndex();
    01101     }
    01102     if (t.GetDepotActionType() & ODATFB_HALT) {
    01103       /* Vehicles are always stopped on entering depots. Do not restart this one. */
    01104       _vehicles_to_autoreplace[v] = false;
    01105       if (v->owner == _local_company) {
    01106         SetDParam(0, v->index);
    01107         AddVehicleNewsItem(STR_NEWS_TRAIN_IS_WAITING + v->type, NS_ADVICE, v->index);
    01108       }
    01109       AI::NewEvent(v->owner, new AIEventVehicleWaitingInDepot(v->index));
    01110     }
    01111   }
    01112 }
    01113
    01114
    01122 void VehicleMove(Vehicle *v, bool update_viewport)
    01123 {
    01124   int img = v->cur_image;
    01125   Point pt = RemapCoords(v->x_pos + v->x_offs, v->y_pos + v->y_offs, v->z_pos);
    01126   const Sprite *spr = GetSprite(img, ST_NORMAL);
    01127
    01128   pt.x += spr->x_offs;
    01129   pt.y += spr->y_offs;
    01130
    01131   UpdateVehiclePosHash(v, pt.x, pt.y);
    01132
    01133   Rect old_coord = v->coord;
    01134   v->coord.left   = pt.x;
    01135   v->coord.top    = pt.y;
    01136   v->coord.right  = pt.x + spr->width + 2;
    01137   v->coord.bottom = pt.y + spr->height + 2;
    01138
    01139   if (update_viewport) {
    01140     MarkAllViewportsDirty(
    01141       min(old_coord.left,   v->coord.left),
    01142       min(old_coord.top,    v->coord.top),
    01143       max(old_coord.right,  v->coord.right) + 1,
    01144       max(old_coord.bottom, v->coord.bottom) + 1
    01145     );
    01146   }
    01147 }
    01148
    01157 void MarkSingleVehicleDirty(const Vehicle *v)
    01158 {
    01159   MarkAllViewportsDirty(v->coord.left, v->coord.top, v->coord.right + 1, v->coord.bottom + 1);
    01160 }
    01161
    01166 GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
    01167 {
    01168   static const int8 _delta_coord[16] = {
    01169     -1,-1,-1, 0, 1, 1, 1, 0, /* x */
    01170     -1, 0, 1, 1, 1, 0,-1,-1, /* y */
    01171   };
    01172
    01173   int x = v->x_pos + _delta_coord[v->direction];
    01174   int y = v->y_pos + _delta_coord[v->direction + 8];
    01175
    01176   GetNewVehiclePosResult gp;
    01177   gp.x = x;
    01178   gp.y = y;
    01179   gp.old_tile = v->tile;
    01180   gp.new_tile = TileVirtXY(x, y);
    01181   return gp;
    01182 }
    01183
    01184 static const Direction _new_direction_table[] = {
    01185   DIR_N,  DIR_NW, DIR_W,
    01186   DIR_NE, DIR_SE, DIR_SW,
    01187   DIR_E,  DIR_SE, DIR_S
    01188 };
    01189
    01190 Direction GetDirectionTowards(const Vehicle *v, int x, int y)
    01191 {
    01192   int i = 0;
    01193
    01194   if (y >= v->y_pos) {
    01195     if (y != v->y_pos) i += 3;
    01196     i += 3;
    01197   }
    01198
    01199   if (x >= v->x_pos) {
    01200     if (x != v->x_pos) i++;
    01201     i++;
    01202   }
    01203
    01204   Direction dir = v->direction;
    01205
    01206   DirDiff dirdiff = DirDifference(_new_direction_table[i], dir);
    01207   if (dirdiff == DIRDIFF_SAME) return dir;
    01208   return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
    01209 }
    01210
    01220 VehicleEnterTileStatus VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
    01221 {
    01222   return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
    01223 }
    01224
    01225 FreeUnitIDGenerator::FreeUnitIDGenerator(VehicleType type, CompanyID owner) : cache(NULL), maxid(0), curid(0)
    01226 {
    01227   /* Find maximum */
    01228   const Vehicle *v;
    01229   FOR_ALL_VEHICLES(v) {
    01230     if (v->type == type && v->owner == owner) {
    01231       this->maxid = max<UnitID>(this->maxid, v->unitnumber);
    01232     }
    01233   }
    01234
    01235   if (this->maxid == 0) return;
    01236
    01237   /* Reserving 'maxid + 2' because we need:
    01238    * - space for the last item (with v->unitnumber == maxid)
    01239    * - one free slot working as loop terminator in FreeUnitIDGenerator::NextID() */
    01240   this->cache = CallocT<bool>(this->maxid + 2);
    01241
    01242   /* Fill the cache */
    01243   FOR_ALL_VEHICLES(v) {
    01244     if (v->type == type && v->owner == owner) {
    01245       this->cache[v->unitnumber] = true;
    01246     }
    01247   }
    01248 }
    01249
    01250 UnitID FreeUnitIDGenerator::NextID()
    01251 {
    01252   if (this->maxid <= this->curid) return ++this->curid;
    01253
    01254   while (this->cache[++this->curid]) { } // it will stop, we reserved more space than needed
    01255
    01256   return this->curid;
    01257 }
    01258
    01264 UnitID GetFreeUnitNumber(VehicleType type)
    01265 {
    01266   /* Check whether it is allowed to build another vehicle. */
    01267   uint max_veh;
    01268   switch (type) {
    01269     case VEH_TRAIN:    max_veh = _settings_game.vehicle.max_trains;   break;
    01270     case VEH_ROAD:     max_veh = _settings_game.vehicle.max_roadveh;  break;
    01271     case VEH_SHIP:     max_veh = _settings_game.vehicle.max_ships;    break;
    01272     case VEH_AIRCRAFT: max_veh = _settings_game.vehicle.max_aircraft; break;
    01273     default: NOT_REACHED();
    01274   }
    01275
    01276   uint amounts[4];
    01277   CountCompanyVehicles(_current_company, amounts);
    01278   assert((uint)type < lengthof(amounts));
    01279   if (amounts[type] >= max_veh) return UINT16_MAX; // Currently already at the limit, no room to make a new one.
    01280
    01281   FreeUnitIDGenerator gen(type, _current_company);
    01282
    01283   return gen.NextID();
    01284 }
    01285
    01286
    01295 bool CanBuildVehicleInfrastructure(VehicleType type)
    01296 {
    01297   assert(IsCompanyBuildableVehicleType(type));
    01298
    01299   if (!Company::IsValidID(_local_company)) return false;
    01300   if (_settings_client.gui.always_build_infrastructure) return true;
    01301
    01302   UnitID max;
    01303   switch (type) {
    01304     case VEH_TRAIN:    max = _settings_game.vehicle.max_trains; break;
    01305     case VEH_ROAD:     max = _settings_game.vehicle.max_roadveh; break;
    01306     case VEH_SHIP:     max = _settings_game.vehicle.max_ships; break;
    01307     case VEH_AIRCRAFT: max = _settings_game.vehicle.max_aircraft; break;
    01308     default: NOT_REACHED();
    01309   }
    01310
    01311   /* We can build vehicle infrastructure when we may build the vehicle type */
    01312   if (max > 0) {
    01313     /* Can we actually build the vehicle type? */
    01314     const Engine *e;
    01315     FOR_ALL_ENGINES_OF_TYPE(e, type) {
    01316       if (HasBit(e->company_avail, _local_company)) return true;
    01317     }
    01318     return false;
    01319   }
    01320
    01321   /* We should be able to build infrastructure when we have the actual vehicle type */
    01322   const Vehicle *v;
    01323   FOR_ALL_VEHICLES(v) {
    01324     if (v->owner == _local_company && v->type == type) return true;
    01325   }
    01326
    01327   return false;
    01328 }
    01329
    01330
    01340 const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, byte livery_setting)
    01341 {
    01342   const Company *c = Company::Get(company);
    01343   LiveryScheme scheme = LS_DEFAULT;
    01344   CargoID cargo_type = v == NULL ? (CargoID)CT_INVALID : v->cargo_type;
    01345
    01346   /* The default livery is always available for use, but its in_use flag determines
    01347    * whether any _other_ liveries are in use. */
    01348   if (c->livery[LS_DEFAULT].in_use && (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company))) {
    01349     /* Determine the livery scheme to use */
    01350     const Engine *e = Engine::Get(engine_type);
    01351     switch (e->type) {
    01352       default: NOT_REACHED();
    01353       case VEH_TRAIN: {
    01354         if (v != NULL && parent_engine_type != INVALID_ENGINE && (UsesWagonOverride(v) || (Train::From(v)->IsArticulatedPart() && e->u.rail.railveh_type != RAILVEH_WAGON))) {
    01355           /* Wagonoverrides use the coloir scheme of the front engine.
    01356            * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */
    01357           engine_type = parent_engine_type;
    01358           e = Engine::Get(engine_type);
    01359           /* Note: Luckily cargo_type is not needed for engines */
    01360         }
    01361
    01362         if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01363         if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01364         if (e->u.rail.railveh_type == RAILVEH_WAGON) {
    01365           if (!CargoSpec::Get(cargo_type)->is_freight) {
    01366             if (parent_engine_type == INVALID_ENGINE) {
    01367               scheme = LS_PASSENGER_WAGON_STEAM;
    01368             } else {
    01369               switch (RailVehInfo(parent_engine_type)->engclass) {
    01370                 default: NOT_REACHED();
    01371                 case EC_STEAM:    scheme = LS_PASSENGER_WAGON_STEAM;    break;
    01372                 case EC_DIESEL:   scheme = LS_PASSENGER_WAGON_DIESEL;   break;
    01373                 case EC_ELECTRIC: scheme = LS_PASSENGER_WAGON_ELECTRIC; break;
    01374                 case EC_MONORAIL: scheme = LS_PASSENGER_WAGON_MONORAIL; break;
    01375                 case EC_MAGLEV:   scheme = LS_PASSENGER_WAGON_MAGLEV;   break;
    01376               }
    01377             }
    01378           } else {
    01379             scheme = LS_FREIGHT_WAGON;
    01380           }
    01381         } else {
    01382           bool is_mu = HasBit(e->info.misc_flags, EF_RAIL_IS_MU);
    01383
    01384           switch (e->u.rail.engclass) {
    01385             default: NOT_REACHED();
    01386             case EC_STEAM:    scheme = LS_STEAM; break;
    01387             case EC_DIESEL:   scheme = is_mu ? LS_DMU : LS_DIESEL;   break;
    01388             case EC_ELECTRIC: scheme = is_mu ? LS_EMU : LS_ELECTRIC; break;
    01389             case EC_MONORAIL: scheme = LS_MONORAIL; break;
    01390             case EC_MAGLEV:   scheme = LS_MAGLEV; break;
    01391           }
    01392         }
    01393         break;
    01394       }
    01395
    01396       case VEH_ROAD: {
    01397         /* Always use the livery of the front */
    01398         if (v != NULL && parent_engine_type != INVALID_ENGINE) {
    01399           engine_type = parent_engine_type;
    01400           e = Engine::Get(engine_type);
    01401           cargo_type = v->First()->cargo_type;
    01402         }
    01403         if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01404         if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01405
    01406         /* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */
    01407         if (HasBit(e->info.misc_flags, EF_ROAD_TRAM)) {
    01408           /* Tram */
    01409           scheme = IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
    01410         } else {
    01411           /* Bus or truck */
    01412           scheme = IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_BUS : LS_TRUCK;
    01413         }
    01414         break;
    01415       }
    01416
    01417       case VEH_SHIP: {
    01418         if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
    01419         if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
    01420         scheme = IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
    01421         break;
    01422       }
    01423
    01424       case VEH_AIRCRAFT: {
    01425         switch (e->u.air.subtype) {
    01426           case AIR_HELI: scheme = LS_HELICOPTER; break;
    01427           case AIR_CTOL: scheme = LS_SMALL_PLANE; break;
    01428           case AIR_CTOL | AIR_FAST: scheme = LS_LARGE_PLANE; break;
    01429         }
    01430         break;
    01431       }
    01432     }
    01433
    01434     /* Switch back to the default scheme if the resolved scheme is not in use */
    01435     if (!c->livery[scheme].in_use) scheme = LS_DEFAULT;
    01436   }
    01437
    01438   return &c->livery[scheme];
    01439 }
    01440
    01441
    01442 static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
    01443 {
    01444   PaletteID map = (v != NULL) ? v->colourmap : PAL_NONE;
    01445
    01446   /* Return cached value if any */
    01447   if (map != PAL_NONE) return map;
    01448
    01449   const Engine *e = Engine::Get(engine_type);
    01450
    01451   /* Check if we should use the colour map callback */
    01452   if (HasBit(e->info.callback_mask, CBM_VEHICLE_COLOUR_REMAP)) {
    01453     uint16 callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
    01454     /* A return value of 0xC000 is stated to "use the default two-colour
    01455      * maps" which happens to be the failure action too... */
    01456     if (callback != CALLBACK_FAILED && callback != 0xC000) {
    01457       map = GB(callback, 0, 14);
    01458       /* If bit 14 is set, then the company colours are applied to the
    01459        * map else it's returned as-is. */
    01460       if (!HasBit(callback, 14)) {
    01461         /* Update cache */
    01462         if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
    01463         return map;
    01464       }
    01465     }
    01466   }
    01467
    01468   bool twocc = HasBit(e->info.misc_flags, EF_USES_2CC);
    01469
    01470   if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
    01471
    01472   /* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
    01473   if (!Company::IsValidID(company)) return map;
    01474
    01475   const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries);
    01476
    01477   map += livery->colour1;
    01478   if (twocc) map += livery->colour2 * 16;
    01479
    01480   /* Update cache */
    01481   if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
    01482   return map;
    01483 }
    01484
    01485 PaletteID GetEnginePalette(EngineID engine_type, CompanyID company)
    01486 {
    01487   return GetEngineColourMap(engine_type, company, INVALID_ENGINE, NULL);
    01488 }
    01489
    01490 PaletteID GetVehiclePalette(const Vehicle *v)
    01491 {
    01492   if (v->type == VEH_TRAIN) {
    01493     return GetEngineColourMap(v->engine_type, v->owner, Train::From(v)->tcache.first_engine, v);
    01494   } else if (v->type == VEH_ROAD) {
    01495     return GetEngineColourMap(v->engine_type, v->owner, RoadVehicle::From(v)->rcache.first_engine, v);
    01496   }
    01497
    01498   return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
    01499 }
    01500
    01509 uint GetVehicleCapacity(const Vehicle *v, uint16 *mail_capacity)
    01510 {
    01511   if (mail_capacity != NULL) *mail_capacity = 0;
    01512   const Engine *e = Engine::Get(v->engine_type);
    01513
    01514   if (!e->CanCarryCargo()) return 0;
    01515
    01516   if (mail_capacity != NULL && e->type == VEH_AIRCRAFT && IsCargoInClass(v->cargo_type, CC_PASSENGERS)) {
    01517     *mail_capacity = GetVehicleProperty(v, PROP_AIRCRAFT_MAIL_CAPACITY, e->u.air.mail_capacity);
    01518   }
    01519   CargoID default_cargo = e->GetDefaultCargoType();
    01520
    01521   /* Check the refit capacity callback if we are not in the default configuration.
    01522    * Note: This might change to become more consistent/flexible/sane, esp. when default cargo is first refittable. */
    01523   if (HasBit(e->info.callback_mask, CBM_VEHICLE_REFIT_CAPACITY) &&
    01524       (default_cargo != v->cargo_type || v->cargo_subtype != 0)) {
    01525     uint16 callback = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, v->engine_type, v);
    01526     if (callback != CALLBACK_FAILED) return callback;
    01527   }
    01528
    01529   /* Get capacity according to property resp. CB */
    01530   uint capacity;
    01531   switch (e->type) {
    01532     case VEH_TRAIN:    capacity = GetVehicleProperty(v, PROP_TRAIN_CARGO_CAPACITY,        e->u.rail.capacity); break;
    01533     case VEH_ROAD:     capacity = GetVehicleProperty(v, PROP_ROADVEH_CARGO_CAPACITY,      e->u.road.capacity); break;
    01534     case VEH_SHIP:     capacity = GetVehicleProperty(v, PROP_SHIP_CARGO_CAPACITY,         e->u.ship.capacity); break;
    01535     case VEH_AIRCRAFT: capacity = GetVehicleProperty(v, PROP_AIRCRAFT_PASSENGER_CAPACITY, e->u.air.passenger_capacity); break;
    01536     default: NOT_REACHED();
    01537   }
    01538
    01539   /* Apply multipliers depending on cargo- and vehicletype.
    01540    * Note: This might change to become more consistent/flexible. */
    01541   if (e->type != VEH_SHIP) {
    01542     if (e->type == VEH_AIRCRAFT) {
    01543       if (!IsCargoInClass(v->cargo_type, CC_PASSENGERS)) {
    01544         capacity += GetVehicleProperty(v, PROP_AIRCRAFT_MAIL_CAPACITY, e->u.air.mail_capacity);
    01545       }
    01546       if (v->cargo_type == CT_MAIL) return capacity;
    01547     } else {
    01548       switch (default_cargo) {
    01549         case CT_PASSENGERS: break;
    01550         case CT_MAIL:
    01551         case CT_GOODS: capacity *= 2; break;
    01552         default:       capacity *= 4; break;
    01553       }
    01554     }
    01555     switch (v->cargo_type) {
    01556       case CT_PASSENGERS: break;
    01557       case CT_MAIL:
    01558       case CT_GOODS: capacity /= 2; break;
    01559       default:       capacity /= 4; break;
    01560     }
    01561   }
    01562
    01563   return capacity;
    01564 }
    01565
    01566
    01567 void Vehicle::BeginLoading()
    01568 {
    01569   assert(IsTileType(tile, MP_STATION) || type == VEH_SHIP);
    01570
    01571   if (this->current_order.IsType(OT_GOTO_STATION) &&
    01572       this->current_order.GetDestination() == this->last_station_visited) {
    01573     current_order.MakeLoading(true);
    01574     UpdateVehicleTimetable(this, true);
    01575
    01576     /* Furthermore add the Non Stop flag to mark that this station
    01577      * is the actual destination of the vehicle, which is (for example)
    01578      * necessary to be known for HandleTrainLoading to determine
    01579      * whether the train is lost or not; not marking a train lost
    01580      * that arrives at random stations is bad. */
    01581     this->current_order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
    01582
    01583   } else {
    01584     current_order.MakeLoading(false);
    01585   }
    01586
    01587   Station::Get(this->last_station_visited)->loading_vehicles.push_back(this);
    01588
    01589   PrepareUnload(this);
    01590
    01591   SetWindowDirty(GetWindowClassForVehicleType(this->type), this->owner);
    01592   SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    01593   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
    01594   SetWindowDirty(WC_STATION_VIEW, this->last_station_visited);
    01595
    01596   Station::Get(this->last_station_visited)->MarkTilesDirty(true);
    01597   this->cur_speed = 0;
    01598   this->MarkDirty();
    01599 }
    01600
    01601 void Vehicle::LeaveStation()
    01602 {
    01603   assert(current_order.IsType(OT_LOADING));
    01604
    01605   delete this->cargo_payment;
    01606
    01607   /* Only update the timetable if the vehicle was supposed to stop here. */
    01608   if (current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE) UpdateVehicleTimetable(this, false);
    01609
    01610   current_order.MakeLeaveStation();
    01611   Station *st = Station::Get(this->last_station_visited);
    01612   st->loading_vehicles.remove(this);
    01613
    01614   HideFillingPercent(&this->fill_percent_te_id);
    01615
    01616   if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) {
    01617     /* Trigger station animation (trains only) */
    01618     if (IsTileType(this->tile, MP_STATION)) StationAnimationTrigger(st, this->tile, STAT_ANIM_TRAIN_DEPARTS);
    01619
    01620     /* Try to reserve a path when leaving the station as we
    01621      * might not be marked as wanting a reservation, e.g.
    01622      * when an overlength train gets turned around in a station. */
    01623     if (UpdateSignalsOnSegment(this->tile, TrackdirToExitdir(this->GetVehicleTrackdir()), this->owner) == SIGSEG_PBS || _settings_game.pf.reserve_paths) {
    01624       TryPathReserve(Train::From(this), true, true);
    01625     }
    01626   }
    01627 }
    01628
    01629
    01630 void Vehicle::HandleLoading(bool mode)
    01631 {
    01632   switch (this->current_order.GetType()) {
    01633     case OT_LOADING: {
    01634       uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0);
    01635
    01636       /* Not the first call for this tick, or still loading */
    01637       if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) ||
    01638           (_settings_game.order.timetabling && this->current_order_time < wait_time)) return;
    01639
    01640       this->PlayLeaveStationSound();
    01641
    01642       bool at_destination_station = this->current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE;
    01643       this->LeaveStation();
    01644
    01645       /* If this was not the final order, don't remove it from the list. */
    01646       if (!at_destination_station) return;
    01647       break;
    01648     }
    01649
    01650     case OT_DUMMY: break;
    01651
    01652     default: return;
    01653   }
    01654
    01655   this->IncrementOrderIndex();
    01656 }
    01657
    01658 CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command)
    01659 {
    01660   if (!CheckOwnership(this->owner)) return CMD_ERROR;
    01661   if (this->vehstatus & VS_CRASHED) return CMD_ERROR;
    01662   if (this->IsStoppedInDepot()) return CMD_ERROR;
    01663
    01664   if (this->current_order.IsType(OT_GOTO_DEPOT)) {
    01665     bool halt_in_depot = (this->current_order.GetDepotActionType() & ODATFB_HALT) != 0;
    01666     if (!!(command & DEPOT_SERVICE) == halt_in_depot) {
    01667       /* We called with a different DEPOT_SERVICE setting.
    01668        * Now we change the setting to apply the new one and let the vehicle head for the same depot.
    01669        * Note: the if is (true for requesting service == true for ordered to stop in depot)          */
    01670       if (flags & DC_EXEC) {
    01671         this->current_order.SetDepotOrderType(ODTF_MANUAL);
    01672         this->current_order.SetDepotActionType(halt_in_depot ? ODATF_SERVICE_ONLY : ODATFB_HALT);
    01673         SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    01674       }
    01675       return CommandCost();
    01676     }
    01677
    01678     if (command & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
    01679     if (flags & DC_EXEC) {
    01680       /* If the orders to 'goto depot' are in the orders list (forced servicing),
    01681        * then skip to the next order; effectively cancelling this forced service */
    01682       if (this->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) this->IncrementOrderIndex();
    01683
    01684       this->current_order.MakeDummy();
    01685       SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    01686     }
    01687     return CommandCost();
    01688   }
    01689
    01690   TileIndex location;
    01691   DestinationID destination;
    01692   bool reverse;
    01693   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};
    01694   if (!this->FindClosestDepot(&location, &destination, &reverse)) return_cmd_error(no_depot[this->type]);
    01695
    01696   if (flags & DC_EXEC) {
    01697     if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
    01698
    01699     this->dest_tile = location;
    01700     this->current_order.MakeGoToDepot(destination, ODTF_MANUAL);
    01701     if (!(command & DEPOT_SERVICE)) this->current_order.SetDepotActionType(ODATFB_HALT);
    01702     SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
    01703
    01704     /* If there is no depot in front, reverse automatically (trains only) */
    01705     if (this->type == VEH_TRAIN && reverse) DoCommand(this->tile, this->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
    01706
    01707     if (this->type == VEH_AIRCRAFT) {
    01708       Aircraft *a = Aircraft::From(this);
    01709       if (a->state == FLYING && a->targetairport != destination) {
    01710         /* The aircraft is now heading for a different hangar than the next in the orders */
    01711         extern void AircraftNextAirportPos_and_Order(Aircraft *a);
    01712         AircraftNextAirportPos_and_Order(a);
    01713       }
    01714     }
    01715   }
    01716
    01717   return CommandCost();
    01718
    01719 }
    01720
    01721 void Vehicle::SetNext(Vehicle *next)
    01722 {
    01723   assert(this != next);
    01724
    01725   if (this->next != NULL) {
    01726     /* We had an old next vehicle. Update the first and previous pointers */
    01727     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
    01728       v->first = this->next;
    01729     }
    01730     this->next->previous = NULL;
    01731   }
    01732
    01733   this->next = next;
    01734
    01735   if (this->next != NULL) {
    01736     /* A new next vehicle. Update the first and previous pointers */
    01737     if (this->next->previous != NULL) this->next->previous->next = NULL;
    01738     this->next->previous = this;
    01739     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
    01740       v->first = this->first;
    01741     }
    01742   }
    01743 }
    01744
    01745 void Vehicle::AddToShared(Vehicle *shared_chain)
    01746 {
    01747   assert(this->previous_shared == NULL && this->next_shared == NULL);
    01748
    01749   if (!shared_chain->orders.list) {
    01750     assert(shared_chain->previous_shared == NULL);
    01751     assert(shared_chain->next_shared == NULL);
    01752     this->orders.list = shared_chain->orders.list = new OrderList(NULL, shared_chain);
    01753   }
    01754
    01755   this->next_shared     = shared_chain->next_shared;
    01756   this->previous_shared = shared_chain;
    01757
    01758   shared_chain->next_shared = this;
    01759
    01760   if (this->next_shared != NULL) this->next_shared->previous_shared = this;
    01761
    01762   shared_chain->orders.list->AddVehicle(this);
    01763 }
    01764
    01765 void Vehicle::RemoveFromShared()
    01766 {
    01767   /* Remember if we were first and the old window number before RemoveVehicle()
    01768    * as this changes first if needed. */
    01769   bool were_first = (this->FirstShared() == this);
    01770   uint32 old_window_number = (this->FirstShared()->index << 16) | (this->type << 11) | VLW_SHARED_ORDERS | this->owner;
    01771
    01772   this->orders.list->RemoveVehicle(this);
    01773
    01774   if (!were_first) {
    01775     /* We are not the first shared one, so only relink our previous one. */
    01776     this->previous_shared->next_shared = this->NextShared();
    01777   }
    01778
    01779   if (this->next_shared != NULL) this->next_shared->previous_shared = this->previous_shared;
    01780
    01781
    01782   if (this->orders.list->GetNumVehicles() == 1) {
    01783     /* When there is only one vehicle, remove the shared order list window. */
    01784     DeleteWindowById(GetWindowClassForVehicleType(this->type), old_window_number);
    01785     InvalidateVehicleOrder(this->FirstShared(), 0);
    01786   } else if (were_first) {
    01787     /* If we were the first one, update to the new first one.
    01788      * Note: FirstShared() is already the new first */
    01789     InvalidateWindowData(GetWindowClassForVehicleType(this->type), old_window_number, (this->FirstShared()->index << 16) | (1 << 15));
    01790   }
    01791
    01792   this->next_shared     = NULL;
    01793   this->previous_shared = NULL;
    01794 }
    01795
    01796 void StopAllVehicles()
    01797 {
    01798   Vehicle *v;
    01799   FOR_ALL_VEHICLES(v) {
    01800     /* Code ripped from CmdStartStopTrain. Can't call it, because of
    01801      * ownership problems, so we'll duplicate some code, for now */
    01802     v->vehstatus |= VS_STOPPED;
    01803     v->MarkDirty();
    01804     SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
    01805     SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
    01806   }
    01807 }
    01808
    01809 void VehiclesYearlyLoop()
    01810 {
    01811   Vehicle *v;
    01812   FOR_ALL_VEHICLES(v) {
    01813     if (v->IsPrimaryVehicle()) {
    01814       /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
    01815       Money profit = v->GetDisplayProfitThisYear();
    01816       if (v->age >= 730 && profit < 0) {
    01817         if (_settings_client.gui.vehicle_income_warn && v->owner == _local_company) {
    01818           SetDParam(0, v->index);
    01819           SetDParam(1, profit);
    01820           AddVehicleNewsItem(
    01821             STR_NEWS_VEHICLE_IS_UNPROFITABLE,
    01822             NS_ADVICE,
    01823             v->index
    01824           );
    01825         }
    01826         AI::NewEvent(v->owner, new AIEventVehicleUnprofitable(v->index));
    01827       }
    01828
    01829       v->profit_last_year = v->profit_this_year;
    01830       v->profit_this_year = 0;
    01831       SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
    01832     }
    01833   }
    01834 }
    01835
    01836
    01846 bool CanVehicleUseStation(EngineID engine_type, const Station *st)
    01847 {
    01848   const Engine *e = Engine::GetIfValid(engine_type);
    01849   assert(e != NULL);
    01850
    01851   switch (e->type) {
    01852     case VEH_TRAIN:
    01853       return (st->facilities & FACIL_TRAIN) != 0;
    01854
    01855     case VEH_ROAD:
    01856       /* For road vehicles we need the vehicle to know whether it can actually
    01857        * use the station, but if it doesn't have facilities for RVs it is
    01858        * certainly not possible that the station can be used. */
    01859       return (st->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP)) != 0;
    01860
    01861     case VEH_SHIP:
    01862       return (st->facilities & FACIL_DOCK) != 0;
    01863
    01864     case VEH_AIRCRAFT:
    01865       return (st->facilities & FACIL_AIRPORT) != 0 &&
    01866           (st->Airport()->flags & (e->u.air.subtype & AIR_CTOL ? AirportFTAClass::AIRPLANES : AirportFTAClass::HELICOPTERS)) != 0;
    01867
    01868     default:
    01869       return false;
    01870   }
    01871 }
    01872
    01879 bool CanVehicleUseStation(const Vehicle *v, const Station *st)
    01880 {
    01881   if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != NULL;
    01882
    01883   return CanVehicleUseStation(v->engine_type, st);
    01884 }