vehicle.cpp

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

Generated on Wed Dec 23 23:27:56 2009 for OpenTTD by  doxygen 1.5.6