vehicle.cpp

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

Generated on Fri Jun 3 05:19:01 2011 for OpenTTD by  doxygen 1.6.1