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) ? 184 : (_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   AddSortableSpriteToDraw(image, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
00910     v->x_extent, v->y_extent, v->z_extent, v->z_pos, (v->vehstatus & VS_SHADOW) != 0);
00911 }
00912 
00917 void ViewportAddVehicles(DrawPixelInfo *dpi)
00918 {
00919   /* The bounding rectangle */
00920   const int l = dpi->left;
00921   const int r = dpi->left + dpi->width;
00922   const int t = dpi->top;
00923   const int b = dpi->top + dpi->height;
00924 
00925   /* The hash area to scan */
00926   int xl, xu, yl, yu;
00927 
00928   if (dpi->width + 70 < (1 << (7 + 6))) {
00929     xl = GB(l - 70, 7, 6);
00930     xu = GB(r,      7, 6);
00931   } else {
00932     /* scan whole hash row */
00933     xl = 0;
00934     xu = 0x3F;
00935   }
00936 
00937   if (dpi->height + 70 < (1 << (6 + 6))) {
00938     yl = GB(t - 70, 6, 6) << 6;
00939     yu = GB(b,      6, 6) << 6;
00940   } else {
00941     /* scan whole column */
00942     yl = 0;
00943     yu = 0x3F << 6;
00944   }
00945 
00946   for (int y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
00947     for (int x = xl;; x = (x + 1) & 0x3F) {
00948       const Vehicle *v = _vehicle_position_hash[x + y]; // already masked & 0xFFF
00949 
00950       while (v != NULL) {
00951         if (!(v->vehstatus & VS_HIDDEN) &&
00952             l <= v->coord.right &&
00953             t <= v->coord.bottom &&
00954             r >= v->coord.left &&
00955             b >= v->coord.top) {
00956           DoDrawVehicle(v);
00957         }
00958         v = v->next_hash;
00959       }
00960 
00961       if (x == xu) break;
00962     }
00963 
00964     if (y == yu) break;
00965   }
00966 }
00967 
00975 Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y)
00976 {
00977   Vehicle *found = NULL, *v;
00978   uint dist, best_dist = UINT_MAX;
00979 
00980   if ((uint)(x -= vp->left) >= (uint)vp->width || (uint)(y -= vp->top) >= (uint)vp->height) return NULL;
00981 
00982   x = ScaleByZoom(x, vp->zoom) + vp->virtual_left;
00983   y = ScaleByZoom(y, vp->zoom) + vp->virtual_top;
00984 
00985   FOR_ALL_VEHICLES(v) {
00986     if ((v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0 &&
00987         x >= v->coord.left && x <= v->coord.right &&
00988         y >= v->coord.top && y <= v->coord.bottom) {
00989 
00990       dist = max(
00991         abs(((v->coord.left + v->coord.right) >> 1) - x),
00992         abs(((v->coord.top + v->coord.bottom) >> 1) - y)
00993       );
00994 
00995       if (dist < best_dist) {
00996         found = v;
00997         best_dist = dist;
00998       }
00999     }
01000   }
01001 
01002   return found;
01003 }
01004 
01009 void DecreaseVehicleValue(Vehicle *v)
01010 {
01011   v->value -= v->value >> 8;
01012   SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
01013 }
01014 
01015 static const byte _breakdown_chance[64] = {
01016     3,   3,   3,   3,   3,   3,   3,   3,
01017     4,   4,   5,   5,   6,   6,   7,   7,
01018     8,   8,   9,   9,  10,  10,  11,  11,
01019    12,  13,  13,  13,  13,  14,  15,  16,
01020    17,  19,  21,  25,  28,  31,  34,  37,
01021    40,  44,  48,  52,  56,  60,  64,  68,
01022    72,  80,  90, 100, 110, 120, 130, 140,
01023   150, 170, 190, 210, 230, 250, 250, 250,
01024 };
01025 
01026 void CheckVehicleBreakdown(Vehicle *v)
01027 {
01028   int rel, rel_old;
01029 
01030   /* decrease reliability */
01031   v->reliability = rel = max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
01032   if ((rel_old >> 8) != (rel >> 8)) SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
01033 
01034   if (v->breakdown_ctr != 0 || (v->vehstatus & VS_STOPPED) ||
01035       _settings_game.difficulty.vehicle_breakdowns < 1 ||
01036       v->cur_speed < 5 || _game_mode == GM_MENU) {
01037     return;
01038   }
01039 
01040   uint32 r = Random();
01041 
01042   /* increase chance of failure */
01043   int chance = v->breakdown_chance + 1;
01044   if (Chance16I(1, 25, r)) chance += 25;
01045   v->breakdown_chance = min(255, chance);
01046 
01047   /* calculate reliability value to use in comparison */
01048   rel = v->reliability;
01049   if (v->type == VEH_SHIP) rel += 0x6666;
01050 
01051   /* reduced breakdowns? */
01052   if (_settings_game.difficulty.vehicle_breakdowns == 1) rel += 0x6666;
01053 
01054   /* check if to break down */
01055   if (_breakdown_chance[(uint)min(rel, 0xffff) >> 10] <= v->breakdown_chance) {
01056     v->breakdown_ctr    = GB(r, 16, 6) + 0x3F;
01057     v->breakdown_delay  = GB(r, 24, 7) + 0x80;
01058     v->breakdown_chance = 0;
01059   }
01060 }
01061 
01068 bool Vehicle::HandleBreakdown()
01069 {
01070   /* Possible states for Vehicle::breakdown_ctr
01071    * 0  - vehicle is running normally
01072    * 1  - vehicle is currently broken down
01073    * 2  - vehicle is going to break down now
01074    * >2 - vehicle is counting down to the actual breakdown event */
01075   switch (this->breakdown_ctr) {
01076     case 0:
01077       return false;
01078 
01079     case 2:
01080       this->breakdown_ctr = 1;
01081 
01082       if (this->breakdowns_since_last_service != 255) {
01083         this->breakdowns_since_last_service++;
01084       }
01085 
01086       this->MarkDirty();
01087       SetWindowDirty(WC_VEHICLE_VIEW, this->index);
01088       SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
01089 
01090       if (this->type == VEH_AIRCRAFT) {
01091         /* Aircraft just need this flag, the rest is handled elsewhere */
01092         this->vehstatus |= VS_AIRCRAFT_BROKEN;
01093       } else {
01094         this->cur_speed = 0;
01095 
01096         if (!PlayVehicleSound(this, VSE_BREAKDOWN)) {
01097           SndPlayVehicleFx((_settings_game.game_creation.landscape != LT_TOYLAND) ?
01098             (this->type == VEH_TRAIN ? SND_10_TRAIN_BREAKDOWN : SND_0F_VEHICLE_BREAKDOWN) :
01099             (this->type == VEH_TRAIN ? SND_3A_COMEDY_BREAKDOWN_2 : SND_35_COMEDY_BREAKDOWN), this);
01100         }
01101 
01102         if (!(this->vehstatus & VS_HIDDEN)) {
01103           EffectVehicle *u = CreateEffectVehicleRel(this, 4, 4, 5, EV_BREAKDOWN_SMOKE);
01104           if (u != NULL) u->animation_state = this->breakdown_delay * 2;
01105         }
01106       }
01107       /* FALL THROUGH */
01108     case 1:
01109       /* Aircraft breakdowns end only when arriving at the airport */
01110       if (this->type == VEH_AIRCRAFT) return false;
01111 
01112       /* For trains this function is called twice per tick, so decrease v->breakdown_delay at half the rate */
01113       if ((this->tick_counter & (this->type == VEH_TRAIN ? 3 : 1)) == 0) {
01114         if (--this->breakdown_delay == 0) {
01115           this->breakdown_ctr = 0;
01116           this->MarkDirty();
01117           SetWindowDirty(WC_VEHICLE_VIEW, this->index);
01118         }
01119       }
01120       return true;
01121 
01122     default:
01123       if (!this->current_order.IsType(OT_LOADING)) this->breakdown_ctr--;
01124       return false;
01125   }
01126 }
01127 
01132 void AgeVehicle(Vehicle *v)
01133 {
01134   if (v->age < MAX_DAY) v->age++;
01135 
01136   int age = v->age - v->max_age;
01137   if (age == DAYS_IN_LEAP_YEAR * 0 || age == DAYS_IN_LEAP_YEAR * 1 ||
01138       age == DAYS_IN_LEAP_YEAR * 2 || age == DAYS_IN_LEAP_YEAR * 3 || age == DAYS_IN_LEAP_YEAR * 4) {
01139     v->reliability_spd_dec <<= 1;
01140   }
01141 
01142   SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
01143 
01144   /* Don't warn about non-primary or not ours vehicles or vehicles that are crashed */
01145   if (v->Previous() != NULL || v->owner != _local_company || (v->vehstatus & VS_CRASHED) != 0) return;
01146 
01147   /* Don't warn if a renew is active */
01148   if (Company::Get(v->owner)->settings.engine_renew && Engine::Get(v->engine_type)->company_avail != 0) return;
01149 
01150   StringID str;
01151   if (age == -DAYS_IN_LEAP_YEAR) {
01152     str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
01153   } else if (age == 0) {
01154     str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
01155   } else if (age > 0 && (age % DAYS_IN_LEAP_YEAR) == 0) {
01156     str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
01157   } else {
01158     return;
01159   }
01160 
01161   SetDParam(0, v->index);
01162   AddVehicleNewsItem(str, NS_ADVICE, v->index);
01163 }
01164 
01171 uint8 CalcPercentVehicleFilled(const Vehicle *v, StringID *colour)
01172 {
01173   int count = 0;
01174   int max = 0;
01175   int cars = 0;
01176   int unloading = 0;
01177   bool loading = false;
01178 
01179   const Vehicle *u = v;
01180   /* The station may be NULL when the (colour) string does not need to be set. */
01181   const Station *st = Station::GetIfValid(v->last_station_visited);
01182   assert(colour == NULL || st != NULL);
01183 
01184   /* Count up max and used */
01185   for (; v != NULL; v = v->Next()) {
01186     count += v->cargo.Count();
01187     max += v->cargo_cap;
01188     if (v->cargo_cap != 0 && colour != NULL) {
01189       unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0;
01190       loading |= !(u->current_order.GetLoadType() & OLFB_NO_LOAD) && st->goods[v->cargo_type].days_since_pickup != 255;
01191       cars++;
01192     }
01193   }
01194 
01195   if (colour != NULL) {
01196     if (unloading == 0 && loading) {
01197       *colour = STR_PERCENT_UP;
01198     } else if (cars == unloading || !loading) {
01199       *colour = STR_PERCENT_DOWN;
01200     } else {
01201       *colour = STR_PERCENT_UP_DOWN;
01202     }
01203   }
01204 
01205   /* Train without capacity */
01206   if (max == 0) return 100;
01207 
01208   /* Return the percentage */
01209   return (count * 100) / max;
01210 }
01211 
01216 void VehicleEnterDepot(Vehicle *v)
01217 {
01218   /* Always work with the front of the vehicle */
01219   assert(v == v->First());
01220 
01221   switch (v->type) {
01222     case VEH_TRAIN: {
01223       Train *t = Train::From(v);
01224       SetWindowClassesDirty(WC_TRAINS_LIST);
01225       /* Clear path reservation */
01226       SetDepotReservation(t->tile, false);
01227       if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(t->tile);
01228 
01229       UpdateSignalsOnSegment(t->tile, INVALID_DIAGDIR, t->owner);
01230       t->wait_counter = 0;
01231       t->force_proceed = TFP_NONE;
01232       ClrBit(t->flags, VRF_TOGGLE_REVERSE);
01233       t->ConsistChanged(true);
01234       break;
01235     }
01236 
01237     case VEH_ROAD:
01238       SetWindowClassesDirty(WC_ROADVEH_LIST);
01239       break;
01240 
01241     case VEH_SHIP: {
01242       SetWindowClassesDirty(WC_SHIPS_LIST);
01243       Ship *ship = Ship::From(v);
01244       ship->state = TRACK_BIT_DEPOT;
01245       ship->UpdateCache();
01246       ship->UpdateViewport(true, true);
01247       SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
01248       break;
01249     }
01250 
01251     case VEH_AIRCRAFT:
01252       SetWindowClassesDirty(WC_AIRCRAFT_LIST);
01253       HandleAircraftEnterHangar(Aircraft::From(v));
01254       break;
01255     default: NOT_REACHED();
01256   }
01257   SetWindowDirty(WC_VEHICLE_VIEW, v->index);
01258 
01259   if (v->type != VEH_TRAIN) {
01260     /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
01261      * 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 */
01262     InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
01263   }
01264   SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
01265 
01266   v->vehstatus |= VS_HIDDEN;
01267   v->cur_speed = 0;
01268 
01269   VehicleServiceInDepot(v);
01270 
01271   TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
01272 
01273   if (v->current_order.IsType(OT_GOTO_DEPOT)) {
01274     SetWindowDirty(WC_VEHICLE_VIEW, v->index);
01275 
01276     const Order *real_order = v->GetOrder(v->cur_real_order_index);
01277     Order t = v->current_order;
01278     v->current_order.MakeDummy();
01279 
01280     /* Test whether we are heading for this depot. If not, do nothing.
01281      * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
01282     if ((t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) &&
01283         real_order != NULL && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) &&
01284         (v->type == VEH_AIRCRAFT ? t.GetDestination() != GetStationIndex(v->tile) : v->dest_tile != v->tile)) {
01285       /* We are heading for another depot, keep driving. */
01286       return;
01287     }
01288 
01289     if (t.IsRefit()) {
01290       Backup<CompanyByte> cur_company(_current_company, v->owner, FILE_LINE);
01291       CommandCost cost = DoCommand(v->tile, v->index, t.GetRefitCargo() | t.GetRefitSubtype() << 8, DC_EXEC, GetCmdRefitVeh(v));
01292       cur_company.Restore();
01293 
01294       if (cost.Failed()) {
01295         _vehicles_to_autoreplace[v] = false;
01296         if (v->owner == _local_company) {
01297           /* Notify the user that we stopped the vehicle */
01298           SetDParam(0, v->index);
01299           AddVehicleNewsItem(STR_NEWS_ORDER_REFIT_FAILED, NS_ADVICE, v->index);
01300         }
01301       } else if (cost.GetCost() != 0) {
01302         v->profit_this_year -= cost.GetCost() << 8;
01303         if (v->owner == _local_company) {
01304           ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
01305         }
01306       }
01307     }
01308 
01309     if (t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
01310       /* Part of orders */
01311       v->DeleteUnreachedAutoOrders();
01312       UpdateVehicleTimetable(v, true);
01313       v->IncrementAutoOrderIndex();
01314     }
01315     if (t.GetDepotActionType() & ODATFB_HALT) {
01316       /* Vehicles are always stopped on entering depots. Do not restart this one. */
01317       _vehicles_to_autoreplace[v] = false;
01318       if (v->owner == _local_company) {
01319         SetDParam(0, v->index);
01320         AddVehicleNewsItem(STR_NEWS_TRAIN_IS_WAITING + v->type, NS_ADVICE, v->index);
01321       }
01322       AI::NewEvent(v->owner, new AIEventVehicleWaitingInDepot(v->index));
01323     }
01324   }
01325 }
01326 
01327 
01335 void VehicleMove(Vehicle *v, bool update_viewport)
01336 {
01337   int img = v->cur_image;
01338   Point pt = RemapCoords(v->x_pos + v->x_offs, v->y_pos + v->y_offs, v->z_pos);
01339   const Sprite *spr = GetSprite(img, ST_NORMAL);
01340 
01341   pt.x += spr->x_offs;
01342   pt.y += spr->y_offs;
01343 
01344   UpdateVehiclePosHash(v, pt.x, pt.y);
01345 
01346   Rect old_coord = v->coord;
01347   v->coord.left   = pt.x;
01348   v->coord.top    = pt.y;
01349   v->coord.right  = pt.x + spr->width + 2;
01350   v->coord.bottom = pt.y + spr->height + 2;
01351 
01352   if (update_viewport) {
01353     MarkAllViewportsDirty(
01354       min(old_coord.left,   v->coord.left),
01355       min(old_coord.top,    v->coord.top),
01356       max(old_coord.right,  v->coord.right) + 1,
01357       max(old_coord.bottom, v->coord.bottom) + 1
01358     );
01359   }
01360 }
01361 
01370 void MarkSingleVehicleDirty(const Vehicle *v)
01371 {
01372   MarkAllViewportsDirty(v->coord.left, v->coord.top, v->coord.right + 1, v->coord.bottom + 1);
01373 }
01374 
01380 GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
01381 {
01382   static const int8 _delta_coord[16] = {
01383     -1,-1,-1, 0, 1, 1, 1, 0, /* x */
01384     -1, 0, 1, 1, 1, 0,-1,-1, /* y */
01385   };
01386 
01387   int x = v->x_pos + _delta_coord[v->direction];
01388   int y = v->y_pos + _delta_coord[v->direction + 8];
01389 
01390   GetNewVehiclePosResult gp;
01391   gp.x = x;
01392   gp.y = y;
01393   gp.old_tile = v->tile;
01394   gp.new_tile = TileVirtXY(x, y);
01395   return gp;
01396 }
01397 
01398 static const Direction _new_direction_table[] = {
01399   DIR_N,  DIR_NW, DIR_W,
01400   DIR_NE, DIR_SE, DIR_SW,
01401   DIR_E,  DIR_SE, DIR_S
01402 };
01403 
01404 Direction GetDirectionTowards(const Vehicle *v, int x, int y)
01405 {
01406   int i = 0;
01407 
01408   if (y >= v->y_pos) {
01409     if (y != v->y_pos) i += 3;
01410     i += 3;
01411   }
01412 
01413   if (x >= v->x_pos) {
01414     if (x != v->x_pos) i++;
01415     i++;
01416   }
01417 
01418   Direction dir = v->direction;
01419 
01420   DirDiff dirdiff = DirDifference(_new_direction_table[i], dir);
01421   if (dirdiff == DIRDIFF_SAME) return dir;
01422   return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
01423 }
01424 
01434 VehicleEnterTileStatus VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
01435 {
01436   return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
01437 }
01438 
01446 FreeUnitIDGenerator::FreeUnitIDGenerator(VehicleType type, CompanyID owner) : cache(NULL), maxid(0), curid(0)
01447 {
01448   /* Find maximum */
01449   const Vehicle *v;
01450   FOR_ALL_VEHICLES(v) {
01451     if (v->type == type && v->owner == owner) {
01452       this->maxid = max<UnitID>(this->maxid, v->unitnumber);
01453     }
01454   }
01455 
01456   if (this->maxid == 0) return;
01457 
01458   /* Reserving 'maxid + 2' because we need:
01459    * - space for the last item (with v->unitnumber == maxid)
01460    * - one free slot working as loop terminator in FreeUnitIDGenerator::NextID() */
01461   this->cache = CallocT<bool>(this->maxid + 2);
01462 
01463   /* Fill the cache */
01464   FOR_ALL_VEHICLES(v) {
01465     if (v->type == type && v->owner == owner) {
01466       this->cache[v->unitnumber] = true;
01467     }
01468   }
01469 }
01470 
01472 UnitID FreeUnitIDGenerator::NextID()
01473 {
01474   if (this->maxid <= this->curid) return ++this->curid;
01475 
01476   while (this->cache[++this->curid]) { } // it will stop, we reserved more space than needed
01477 
01478   return this->curid;
01479 }
01480 
01486 UnitID GetFreeUnitNumber(VehicleType type)
01487 {
01488   /* Check whether it is allowed to build another vehicle. */
01489   uint max_veh;
01490   switch (type) {
01491     case VEH_TRAIN:    max_veh = _settings_game.vehicle.max_trains;   break;
01492     case VEH_ROAD:     max_veh = _settings_game.vehicle.max_roadveh;  break;
01493     case VEH_SHIP:     max_veh = _settings_game.vehicle.max_ships;    break;
01494     case VEH_AIRCRAFT: max_veh = _settings_game.vehicle.max_aircraft; break;
01495     default: NOT_REACHED();
01496   }
01497 
01498   uint amounts[4];
01499   CountCompanyVehicles(_current_company, amounts);
01500   assert((uint)type < lengthof(amounts));
01501   if (amounts[type] >= max_veh) return UINT16_MAX; // Currently already at the limit, no room to make a new one.
01502 
01503   FreeUnitIDGenerator gen(type, _current_company);
01504 
01505   return gen.NextID();
01506 }
01507 
01508 
01517 bool CanBuildVehicleInfrastructure(VehicleType type)
01518 {
01519   assert(IsCompanyBuildableVehicleType(type));
01520 
01521   if (!Company::IsValidID(_local_company)) return false;
01522   if (!_settings_client.gui.disable_unsuitable_building) return true;
01523 
01524   UnitID max;
01525   switch (type) {
01526     case VEH_TRAIN:    max = _settings_game.vehicle.max_trains; break;
01527     case VEH_ROAD:     max = _settings_game.vehicle.max_roadveh; break;
01528     case VEH_SHIP:     max = _settings_game.vehicle.max_ships; break;
01529     case VEH_AIRCRAFT: max = _settings_game.vehicle.max_aircraft; break;
01530     default: NOT_REACHED();
01531   }
01532 
01533   /* We can build vehicle infrastructure when we may build the vehicle type */
01534   if (max > 0) {
01535     /* Can we actually build the vehicle type? */
01536     const Engine *e;
01537     FOR_ALL_ENGINES_OF_TYPE(e, type) {
01538       if (HasBit(e->company_avail, _local_company)) return true;
01539     }
01540     return false;
01541   }
01542 
01543   /* We should be able to build infrastructure when we have the actual vehicle type */
01544   const Vehicle *v;
01545   FOR_ALL_VEHICLES(v) {
01546     if (v->owner == _local_company && v->type == type) return true;
01547   }
01548 
01549   return false;
01550 }
01551 
01552 
01560 LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
01561 {
01562   CargoID cargo_type = v == NULL ? (CargoID)CT_INVALID : v->cargo_type;
01563   const Engine *e = Engine::Get(engine_type);
01564   switch (e->type) {
01565     default: NOT_REACHED();
01566     case VEH_TRAIN:
01567       if (v != NULL && parent_engine_type != INVALID_ENGINE && (UsesWagonOverride(v) || (v->IsArticulatedPart() && e->u.rail.railveh_type != RAILVEH_WAGON))) {
01568         /* Wagonoverrides use the colour scheme of the front engine.
01569          * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */
01570         engine_type = parent_engine_type;
01571         e = Engine::Get(engine_type);
01572         /* Note: Luckily cargo_type is not needed for engines */
01573       }
01574 
01575       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
01576       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
01577       if (e->u.rail.railveh_type == RAILVEH_WAGON) {
01578         if (!CargoSpec::Get(cargo_type)->is_freight) {
01579           if (parent_engine_type == INVALID_ENGINE) {
01580             return LS_PASSENGER_WAGON_STEAM;
01581           } else {
01582             switch (RailVehInfo(parent_engine_type)->engclass) {
01583               default: NOT_REACHED();
01584               case EC_STEAM:    return LS_PASSENGER_WAGON_STEAM;
01585               case EC_DIESEL:   return LS_PASSENGER_WAGON_DIESEL;
01586               case EC_ELECTRIC: return LS_PASSENGER_WAGON_ELECTRIC;
01587               case EC_MONORAIL: return LS_PASSENGER_WAGON_MONORAIL;
01588               case EC_MAGLEV:   return LS_PASSENGER_WAGON_MAGLEV;
01589             }
01590           }
01591         } else {
01592           return LS_FREIGHT_WAGON;
01593         }
01594       } else {
01595         bool is_mu = HasBit(e->info.misc_flags, EF_RAIL_IS_MU);
01596 
01597         switch (e->u.rail.engclass) {
01598           default: NOT_REACHED();
01599           case EC_STEAM:    return LS_STEAM;
01600           case EC_DIESEL:   return is_mu ? LS_DMU : LS_DIESEL;
01601           case EC_ELECTRIC: return is_mu ? LS_EMU : LS_ELECTRIC;
01602           case EC_MONORAIL: return LS_MONORAIL;
01603           case EC_MAGLEV:   return LS_MAGLEV;
01604         }
01605       }
01606 
01607     case VEH_ROAD:
01608       /* Always use the livery of the front */
01609       if (v != NULL && parent_engine_type != INVALID_ENGINE) {
01610         engine_type = parent_engine_type;
01611         e = Engine::Get(engine_type);
01612         cargo_type = v->First()->cargo_type;
01613       }
01614       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
01615       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
01616 
01617       /* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */
01618       if (HasBit(e->info.misc_flags, EF_ROAD_TRAM)) {
01619         /* Tram */
01620         return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
01621       } else {
01622         /* Bus or truck */
01623         return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_BUS : LS_TRUCK;
01624       }
01625 
01626     case VEH_SHIP:
01627       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
01628       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
01629       return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
01630 
01631     case VEH_AIRCRAFT:
01632       switch (e->u.air.subtype) {
01633         case AIR_HELI: return LS_HELICOPTER;
01634         case AIR_CTOL: return LS_SMALL_PLANE;
01635         case AIR_CTOL | AIR_FAST: return LS_LARGE_PLANE;
01636         default: NOT_REACHED();
01637       }
01638   }
01639 }
01640 
01650 const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, byte livery_setting)
01651 {
01652   const Company *c = Company::Get(company);
01653   LiveryScheme scheme = LS_DEFAULT;
01654 
01655   /* The default livery is always available for use, but its in_use flag determines
01656    * whether any _other_ liveries are in use. */
01657   if (c->livery[LS_DEFAULT].in_use && (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company))) {
01658     /* Determine the livery scheme to use */
01659     scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
01660 
01661     /* Switch back to the default scheme if the resolved scheme is not in use */
01662     if (!c->livery[scheme].in_use) scheme = LS_DEFAULT;
01663   }
01664 
01665   return &c->livery[scheme];
01666 }
01667 
01668 
01669 static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
01670 {
01671   PaletteID map = (v != NULL) ? v->colourmap : PAL_NONE;
01672 
01673   /* Return cached value if any */
01674   if (map != PAL_NONE) return map;
01675 
01676   const Engine *e = Engine::Get(engine_type);
01677 
01678   /* Check if we should use the colour map callback */
01679   if (HasBit(e->info.callback_mask, CBM_VEHICLE_COLOUR_REMAP)) {
01680     uint16 callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
01681     /* Failure means "use the default two-colour" */
01682     if (callback != CALLBACK_FAILED) {
01683       assert_compile(PAL_NONE == 0); // Returning 0x4000 (resp. 0xC000) conincidences with default value (PAL_NONE)
01684       map = GB(callback, 0, 14);
01685       /* If bit 14 is set, then the company colours are applied to the
01686        * map else it's returned as-is. */
01687       if (!HasBit(callback, 14)) {
01688         /* Update cache */
01689         if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
01690         return map;
01691       }
01692     }
01693   }
01694 
01695   bool twocc = HasBit(e->info.misc_flags, EF_USES_2CC);
01696 
01697   if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
01698 
01699   /* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
01700   if (!Company::IsValidID(company)) return map;
01701 
01702   const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries);
01703 
01704   map += livery->colour1;
01705   if (twocc) map += livery->colour2 * 16;
01706 
01707   /* Update cache */
01708   if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
01709   return map;
01710 }
01711 
01718 PaletteID GetEnginePalette(EngineID engine_type, CompanyID company)
01719 {
01720   return GetEngineColourMap(engine_type, company, INVALID_ENGINE, NULL);
01721 }
01722 
01728 PaletteID GetVehiclePalette(const Vehicle *v)
01729 {
01730   if (v->IsGroundVehicle()) {
01731     return GetEngineColourMap(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v);
01732   }
01733 
01734   return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
01735 }
01736 
01745 uint GetVehicleCapacity(const Vehicle *v, uint16 *mail_capacity)
01746 {
01747   if (mail_capacity != NULL) *mail_capacity = 0;
01748   const Engine *e = Engine::Get(v->engine_type);
01749 
01750   if (!e->CanCarryCargo()) return 0;
01751 
01752   if (mail_capacity != NULL && e->type == VEH_AIRCRAFT && IsCargoInClass(v->cargo_type, CC_PASSENGERS)) {
01753     *mail_capacity = GetVehicleProperty(v, PROP_AIRCRAFT_MAIL_CAPACITY, e->u.air.mail_capacity);
01754   }
01755   CargoID default_cargo = e->GetDefaultCargoType();
01756 
01757   /* Check the refit capacity callback if we are not in the default configuration.
01758    * Note: This might change to become more consistent/flexible/sane, esp. when default cargo is first refittable. */
01759   if (HasBit(e->info.callback_mask, CBM_VEHICLE_REFIT_CAPACITY) &&
01760       (default_cargo != v->cargo_type || v->cargo_subtype != 0)) {
01761     uint16 callback = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, v->engine_type, v);
01762     if (callback != CALLBACK_FAILED) return callback;
01763   }
01764 
01765   /* Get capacity according to property resp. CB */
01766   uint capacity;
01767   switch (e->type) {
01768     case VEH_TRAIN:    capacity = GetVehicleProperty(v, PROP_TRAIN_CARGO_CAPACITY,        e->u.rail.capacity); break;
01769     case VEH_ROAD:     capacity = GetVehicleProperty(v, PROP_ROADVEH_CARGO_CAPACITY,      e->u.road.capacity); break;
01770     case VEH_SHIP:     capacity = GetVehicleProperty(v, PROP_SHIP_CARGO_CAPACITY,         e->u.ship.capacity); break;
01771     case VEH_AIRCRAFT: capacity = GetVehicleProperty(v, PROP_AIRCRAFT_PASSENGER_CAPACITY, e->u.air.passenger_capacity); break;
01772     default: NOT_REACHED();
01773   }
01774 
01775   /* Apply multipliers depending on cargo- and vehicletype.
01776    * Note: This might change to become more consistent/flexible. */
01777   if (e->type != VEH_SHIP) {
01778     if (e->type == VEH_AIRCRAFT) {
01779       if (!IsCargoInClass(v->cargo_type, CC_PASSENGERS)) {
01780         capacity += GetVehicleProperty(v, PROP_AIRCRAFT_MAIL_CAPACITY, e->u.air.mail_capacity);
01781       }
01782       if (v->cargo_type == CT_MAIL) return capacity;
01783     } else {
01784       switch (default_cargo) {
01785         case CT_PASSENGERS: break;
01786         case CT_MAIL:
01787         case CT_GOODS: capacity *= 2; break;
01788         default:       capacity *= 4; break;
01789       }
01790     }
01791     switch (v->cargo_type) {
01792       case CT_PASSENGERS: break;
01793       case CT_MAIL:
01794       case CT_GOODS: capacity /= 2; break;
01795       default:       capacity /= 4; break;
01796     }
01797   }
01798 
01799   return capacity;
01800 }
01801 
01805 void Vehicle::DeleteUnreachedAutoOrders()
01806 {
01807   if (this->IsGroundVehicle()) {
01808     uint16 &gv_flags = this->GetGroundVehicleFlags();
01809     if (HasBit(gv_flags, GVF_SUPPRESS_AUTOMATIC_ORDERS)) {
01810       /* Do not delete orders, only skip them */
01811       ClrBit(gv_flags, GVF_SUPPRESS_AUTOMATIC_ORDERS);
01812       this->cur_auto_order_index = this->cur_real_order_index;
01813       InvalidateVehicleOrder(this, 0);
01814       return;
01815     }
01816   }
01817 
01818   const Order *order = this->GetOrder(this->cur_auto_order_index);
01819   while (order != NULL) {
01820     if (this->cur_auto_order_index == this->cur_real_order_index) break;
01821 
01822     if (order->IsType(OT_AUTOMATIC)) {
01823       /* Delete order effectively deletes order, so get the next before deleting it. */
01824       order = order->next;
01825       DeleteOrder(this, this->cur_auto_order_index);
01826     } else {
01827       /* Skip non-automatic orders, e.g. service-orders */
01828       order = order->next;
01829       this->cur_auto_order_index++;
01830     }
01831 
01832     /* Wrap around */
01833     if (order == NULL) {
01834       order = this->GetOrder(0);
01835       this->cur_auto_order_index = 0;
01836     }
01837   }
01838 }
01839 
01845 void Vehicle::BeginLoading(StationID station)
01846 {
01847   assert(IsTileType(this->tile, MP_STATION) || this->type == VEH_SHIP);
01848 
01849   this->last_station_visited = station;
01850 
01851   if (this->current_order.IsType(OT_GOTO_STATION) &&
01852       this->current_order.GetDestination() == this->last_station_visited) {
01853     this->DeleteUnreachedAutoOrders();
01854 
01855     /* Now both order indices point to the destination station, and we can start loading */
01856     this->current_order.MakeLoading(true);
01857     UpdateVehicleTimetable(this, true);
01858 
01859     /* Furthermore add the Non Stop flag to mark that this station
01860      * is the actual destination of the vehicle, which is (for example)
01861      * necessary to be known for HandleTrainLoading to determine
01862      * whether the train is lost or not; not marking a train lost
01863      * that arrives at random stations is bad. */
01864     this->current_order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
01865 
01866   } else {
01867     assert(this->IsGroundVehicle());
01868     bool suppress_automatic_orders = HasBit(this->GetGroundVehicleFlags(), GVF_SUPPRESS_AUTOMATIC_ORDERS);
01869 
01870     /* We weren't scheduled to stop here. Insert an automatic order
01871      * to show that we are stopping here, but only do that if the order
01872      * list isn't empty. */
01873     Order *in_list = this->GetOrder(this->cur_auto_order_index);
01874     if (in_list != NULL &&
01875         (!in_list->IsType(OT_AUTOMATIC) ||
01876         in_list->GetDestination() != this->last_station_visited)) {
01877       /* Do not create consecutive duplicates of automatic orders */
01878       Order *prev_order = this->cur_auto_order_index > 0 ? this->GetOrder(this->cur_auto_order_index - 1) : NULL;
01879       if (prev_order == NULL ||
01880           (!prev_order->IsType(OT_AUTOMATIC) && !prev_order->IsType(OT_GOTO_STATION)) ||
01881           prev_order->GetDestination() != this->last_station_visited) {
01882 
01883         /* Prefer deleting automatic orders instead of inserting new ones,
01884          * so test whether the right order follows later */
01885         int target_index = this->cur_auto_order_index;
01886         bool found = false;
01887         while (target_index != this->cur_real_order_index) {
01888           const Order *order = this->GetOrder(target_index);
01889           if (order->IsType(OT_AUTOMATIC) && order->GetDestination() == this->last_station_visited) {
01890             found = true;
01891             break;
01892           }
01893           target_index++;
01894           if (target_index >= this->orders.list->GetNumOrders()) target_index = 0;
01895           assert(target_index != this->cur_auto_order_index); // infinite loop?
01896         }
01897 
01898         if (found) {
01899           if (suppress_automatic_orders) {
01900             /* Skip to the found order */
01901             this->cur_auto_order_index = target_index;
01902             InvalidateVehicleOrder(this, 0);
01903           } else {
01904             /* Delete all automatic orders up to the station we just reached */
01905             const Order *order = this->GetOrder(this->cur_auto_order_index);
01906             while (!order->IsType(OT_AUTOMATIC) || order->GetDestination() != this->last_station_visited) {
01907               if (order->IsType(OT_AUTOMATIC)) {
01908                 /* Delete order effectively deletes order, so get the next before deleting it. */
01909                 order = order->next;
01910                 DeleteOrder(this, this->cur_auto_order_index);
01911               } else {
01912                 /* Skip non-automatic orders, e.g. service-orders */
01913                 order = order->next;
01914                 this->cur_auto_order_index++;
01915               }
01916 
01917               /* Wrap around */
01918               if (order == NULL) {
01919                 order = this->GetOrder(0);
01920                 this->cur_auto_order_index = 0;
01921               }
01922               assert(order != NULL);
01923             }
01924           }
01925         } else if (!suppress_automatic_orders && this->orders.list->GetNumOrders() < MAX_VEH_ORDER_ID && Order::CanAllocateItem()) {
01926           /* Insert new automatic order */
01927           Order *auto_order = new Order();
01928           auto_order->MakeAutomatic(this->last_station_visited);
01929           InsertOrder(this, auto_order, this->cur_auto_order_index);
01930           if (this->cur_auto_order_index > 0) --this->cur_auto_order_index;
01931           this->current_order.index = auto_order->index;
01932 
01933           /* InsertOrder disabled creation of automatic orders for all vehicles with the same automatic order.
01934            * Reenable it for this vehicle */
01935           uint16 &gv_flags = this->GetGroundVehicleFlags();
01936           ClrBit(gv_flags, GVF_SUPPRESS_AUTOMATIC_ORDERS);
01937         }
01938       }
01939     }
01940     this->current_order.MakeLoading(false);
01941   }
01942 
01943   UpdateVehicleRouteLinks(this, station);
01944 
01945   /* Save the id of the order which made us arrive here. MakeLoading
01946    * does not overwrite the index so it is still valid here. */
01947   this->last_order_id = this->current_order.index;
01948   this->last_station_loaded = station;
01949 
01950   Station *last_visited = Station::Get(this->last_station_visited);
01951   last_visited->loading_vehicles.push_back(this);
01952 
01953   /* Update the next hop for waiting cargo. */
01954   CargoID cid;
01955   FOR_EACH_SET_CARGO_ID(cid, this->vcache.cached_cargo_mask) {
01956     /* Only update if the last update was at least route_recalc_delay ticks earlier. */
01957     if (CargoHasDestinations(cid) && last_visited->goods[cid].cargo_counter == 0) {
01958       last_visited->goods[cid].cargo.UpdateCargoNextHop(last_visited, cid);
01959       last_visited->goods[cid].cargo_counter = _settings_game.economy.cargodest.route_recalc_delay;
01960     }
01961   }
01962 
01963   PrepareUnload(this);
01964 
01965   SetWindowDirty(GetWindowClassForVehicleType(this->type), this->owner);
01966   SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
01967   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
01968   SetWindowDirty(WC_STATION_VIEW, this->last_station_visited);
01969 
01970   Station::Get(this->last_station_visited)->MarkTilesDirty(true);
01971   this->cur_speed = 0;
01972   this->MarkDirty();
01973 }
01974 
01979 void Vehicle::LeaveStation()
01980 {
01981   assert(this->current_order.IsType(OT_LOADING));
01982 
01983   delete this->cargo_payment;
01984 
01985   /* Only update the timetable if the vehicle was supposed to stop here. */
01986   if (this->current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE) UpdateVehicleTimetable(this, false);
01987 
01988   /* Reset travel time counter. */
01989   this->travel_time = 0;
01990 
01991   this->current_order.MakeLeaveStation();
01992   Station *st = Station::Get(this->last_station_visited);
01993   st->loading_vehicles.remove(this);
01994 
01995   HideFillingPercent(&this->fill_percent_te_id);
01996 
01997   if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) {
01998     /* Trigger station animation (trains only) */
01999     if (IsTileType(this->tile, MP_STATION)) TriggerStationAnimation(st, this->tile, SAT_TRAIN_DEPARTS);
02000 
02001     SetBit(Train::From(this)->flags, VRF_LEAVING_STATION);
02002   }
02003 }
02004 
02005 
02011 void Vehicle::HandleLoading(bool mode)
02012 {
02013   switch (this->current_order.GetType()) {
02014     case OT_LOADING: {
02015       uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0);
02016 
02017       /* Not the first call for this tick, or still loading */
02018       if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || this->current_order_time < wait_time) return;
02019 
02020       this->PlayLeaveStationSound();
02021 
02022       this->LeaveStation();
02023 
02024       /* Only advance to next order if we just loaded at the current one */
02025       const Order *order = this->GetOrder(this->cur_auto_order_index);
02026       if (order == NULL ||
02027           (!order->IsType(OT_AUTOMATIC) && !order->IsType(OT_GOTO_STATION)) ||
02028           order->GetDestination() != this->last_station_visited) {
02029         return;
02030       }
02031       break;
02032     }
02033 
02034     case OT_DUMMY: break;
02035 
02036     default: return;
02037   }
02038 
02039   this->IncrementAutoOrderIndex();
02040 }
02041 
02048 CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command)
02049 {
02050   CommandCost ret = CheckOwnership(this->owner);
02051   if (ret.Failed()) return ret;
02052 
02053   if (this->vehstatus & VS_CRASHED) return CMD_ERROR;
02054   if (this->IsStoppedInDepot()) return CMD_ERROR;
02055 
02056   if (this->current_order.IsType(OT_GOTO_DEPOT)) {
02057     bool halt_in_depot = (this->current_order.GetDepotActionType() & ODATFB_HALT) != 0;
02058     if (!!(command & DEPOT_SERVICE) == halt_in_depot) {
02059       /* We called with a different DEPOT_SERVICE setting.
02060        * Now we change the setting to apply the new one and let the vehicle head for the same depot.
02061        * Note: the if is (true for requesting service == true for ordered to stop in depot)          */
02062       if (flags & DC_EXEC) {
02063         this->current_order.SetDepotOrderType(ODTF_MANUAL);
02064         this->current_order.SetDepotActionType(halt_in_depot ? ODATF_SERVICE_ONLY : ODATFB_HALT);
02065         SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
02066       }
02067       return CommandCost();
02068     }
02069 
02070     if (command & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
02071     if (flags & DC_EXEC) {
02072       /* If the orders to 'goto depot' are in the orders list (forced servicing),
02073        * then skip to the next order; effectively cancelling this forced service */
02074       if (this->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) this->IncrementRealOrderIndex();
02075 
02076       if (this->IsGroundVehicle()) {
02077         uint16 &gv_flags = this->GetGroundVehicleFlags();
02078         SetBit(gv_flags, GVF_SUPPRESS_AUTOMATIC_ORDERS);
02079       }
02080 
02081       this->current_order.MakeDummy();
02082       SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
02083     }
02084     return CommandCost();
02085   }
02086 
02087   TileIndex location;
02088   DestinationID destination;
02089   bool reverse;
02090   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};
02091   if (!this->FindClosestDepot(&location, &destination, &reverse)) return_cmd_error(no_depot[this->type]);
02092 
02093   if (flags & DC_EXEC) {
02094     if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
02095 
02096     if (this->IsGroundVehicle()) {
02097       uint16 &gv_flags = this->GetGroundVehicleFlags();
02098       SetBit(gv_flags, GVF_SUPPRESS_AUTOMATIC_ORDERS);
02099     }
02100 
02101     this->dest_tile = location;
02102     this->current_order.MakeGoToDepot(destination, ODTF_MANUAL);
02103     if (!(command & DEPOT_SERVICE)) this->current_order.SetDepotActionType(ODATFB_HALT);
02104     SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
02105 
02106     /* If there is no depot in front, reverse automatically (trains only) */
02107     if (this->type == VEH_TRAIN && reverse) DoCommand(this->tile, this->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
02108 
02109     if (this->type == VEH_AIRCRAFT) {
02110       Aircraft *a = Aircraft::From(this);
02111       if (a->state == FLYING && a->targetairport != destination) {
02112         /* The aircraft is now heading for a different hangar than the next in the orders */
02113         extern void AircraftNextAirportPos_and_Order(Aircraft *a);
02114         AircraftNextAirportPos_and_Order(a);
02115       }
02116     }
02117   }
02118 
02119   return CommandCost();
02120 
02121 }
02122 
02127 void Vehicle::UpdateVisualEffect(bool allow_power_change)
02128 {
02129   bool powered_before = HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
02130   const Engine *e = Engine::Get(this->engine_type);
02131 
02132   /* Evaluate properties */
02133   byte visual_effect;
02134   switch (e->type) {
02135     case VEH_TRAIN: visual_effect = e->u.rail.visual_effect; break;
02136     case VEH_ROAD:  visual_effect = e->u.road.visual_effect; break;
02137     case VEH_SHIP:  visual_effect = e->u.ship.visual_effect; break;
02138     default:        visual_effect = 1 << VE_DISABLE_EFFECT;  break;
02139   }
02140 
02141   /* Check powered wagon / visual effect callback */
02142   if (HasBit(e->info.callback_mask, CBM_VEHICLE_VISUAL_EFFECT)) {
02143     uint16 callback = GetVehicleCallback(CBID_VEHICLE_VISUAL_EFFECT, 0, 0, this->engine_type, this);
02144 
02145     if (callback != CALLBACK_FAILED) {
02146       callback = GB(callback, 0, 8);
02147       /* Avoid accidentally setting 'visual_effect' to the default value
02148        * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
02149       if (callback == VE_DEFAULT) {
02150         assert(HasBit(callback, VE_DISABLE_EFFECT));
02151         SB(callback, VE_TYPE_START, VE_TYPE_COUNT, 0);
02152       }
02153       visual_effect = callback;
02154     }
02155   }
02156 
02157   /* Apply default values */
02158   if (visual_effect == VE_DEFAULT ||
02159       (!HasBit(visual_effect, VE_DISABLE_EFFECT) && GB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT) == VE_TYPE_DEFAULT)) {
02160     /* Only train engines have default effects.
02161      * Note: This is independent of whether the engine is a front engine or articulated part or whatever. */
02162     if (e->type != VEH_TRAIN || e->u.rail.railveh_type == RAILVEH_WAGON || !IsInsideMM(e->u.rail.engclass, EC_STEAM, EC_MONORAIL)) {
02163       if (visual_effect == VE_DEFAULT) {
02164         visual_effect = 1 << VE_DISABLE_EFFECT;
02165       } else {
02166         SetBit(visual_effect, VE_DISABLE_EFFECT);
02167       }
02168     } else {
02169       if (visual_effect == VE_DEFAULT) {
02170         /* Also set the offset */
02171         visual_effect = (VE_OFFSET_CENTRE - (e->u.rail.engclass == EC_STEAM ? 4 : 0)) << VE_OFFSET_START;
02172       }
02173       SB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT, e->u.rail.engclass - EC_STEAM + VE_TYPE_STEAM);
02174     }
02175   }
02176 
02177   this->vcache.cached_vis_effect = visual_effect;
02178 
02179   if (!allow_power_change && powered_before != HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
02180     ToggleBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
02181     ShowNewGrfVehicleError(this->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_POWERED_WAGON, GBUG_VEH_POWERED_WAGON, false);
02182   }
02183 }
02184 
02185 static const int8 _vehicle_smoke_pos[8] = {
02186   1, 1, 1, 0, -1, -1, -1, 0
02187 };
02188 
02193 void Vehicle::ShowVisualEffect() const
02194 {
02195   assert(this->IsPrimaryVehicle());
02196   bool sound = false;
02197 
02198   /* Do not show any smoke when:
02199    * - vehicle smoke is disabled by the player
02200    * - the vehicle is slowing down or stopped (by the player)
02201    * - the vehicle is moving very slowly
02202    */
02203   if (_settings_game.vehicle.smoke_amount == 0 ||
02204       this->vehstatus & (VS_TRAIN_SLOWING | VS_STOPPED) ||
02205       this->cur_speed < 2) {
02206     return;
02207   }
02208   if (this->type == VEH_TRAIN) {
02209     const Train *t = Train::From(this);
02210     /* For trains, do not show any smoke when:
02211      * - the train is reversing
02212      * - is entering a station with an order to stop there and its speed is equal to maximum station entering speed
02213      */
02214     if (HasBit(t->flags, VRF_REVERSING) ||
02215         (IsRailStationTile(t->tile) && t->IsFrontEngine() && t->current_order.ShouldStopAtStation(t, GetStationIndex(t->tile)) &&
02216         t->cur_speed >= t->Train::GetCurrentMaxSpeed())) {
02217       return;
02218     }
02219   }
02220 
02221   const Vehicle *v = this;
02222 
02223   do {
02224     int effect_offset = GB(v->vcache.cached_vis_effect, VE_OFFSET_START, VE_OFFSET_COUNT) - VE_OFFSET_CENTRE;
02225     byte effect_type = GB(v->vcache.cached_vis_effect, VE_TYPE_START, VE_TYPE_COUNT);
02226     bool disable_effect = HasBit(v->vcache.cached_vis_effect, VE_DISABLE_EFFECT);
02227 
02228     /* Show no smoke when:
02229      * - Smoke has been disabled for this vehicle
02230      * - The vehicle is not visible
02231      * - The vehicle is under a bridge
02232      * - The vehicle is on a depot tile
02233      * - The vehicle is on a tunnel tile
02234      * - The vehicle is a train engine that is currently unpowered */
02235     if (disable_effect ||
02236         v->vehstatus & VS_HIDDEN ||
02237         (MayHaveBridgeAbove(v->tile) && IsBridgeAbove(v->tile)) ||
02238         IsDepotTile(v->tile) ||
02239         IsTunnelTile(v->tile) ||
02240         (v->type == VEH_TRAIN &&
02241         !HasPowerOnRail(Train::From(v)->railtype, GetTileRailType(v->tile)))) {
02242       continue;
02243     }
02244 
02245     int x = _vehicle_smoke_pos[v->direction] * effect_offset;
02246     int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
02247 
02248     if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) {
02249       x = -x;
02250       y = -y;
02251     }
02252 
02253     switch (effect_type) {
02254       case VE_TYPE_STEAM:
02255         /* Steam smoke - amount is gradually falling until vehicle reaches its maximum speed, after that it's normal.
02256          * Details: while vehicle's current speed is gradually increasing, steam plumes' density decreases by one third each
02257          * third of its maximum speed spectrum. Steam emission finally normalises at very close to vehicle's maximum speed.
02258          * REGULATION:
02259          * - instead of 1, 4 / 2^smoke_amount (max. 2) is used to provide sufficient regulation to steam puffs' amount. */
02260         if (GB(v->tick_counter, 0, ((4 >> _settings_game.vehicle.smoke_amount) + ((this->cur_speed * 3) / this->vcache.cached_max_speed))) == 0) {
02261           CreateEffectVehicleRel(v, x, y, 10, EV_STEAM_SMOKE);
02262           sound = true;
02263         }
02264         break;
02265 
02266       case VE_TYPE_DIESEL: {
02267         /* Diesel smoke - thicker when vehicle is starting, gradually subsiding till it reaches its maximum speed
02268          * when smoke emission stops.
02269          * Details: Vehicle's (max.) speed spectrum is divided into 32 parts. When max. speed is reached, chance for smoke
02270          * emission erodes by 32 (1/4). For trains, power and weight come in handy too to either increase smoke emission in
02271          * 6 steps (1000HP each) if the power is low or decrease smoke emission in 6 steps (512 tonnes each) if the train
02272          * isn't overweight. Power and weight contributions are expressed in a way that neither extreme power, nor
02273          * extreme weight can ruin the balance (e.g. FreightWagonMultiplier) in the formula. When the vehicle reaches
02274          * maximum speed no diesel_smoke is emitted.
02275          * REGULATION:
02276          * - up to which speed a diesel vehicle is emitting smoke (with reduced/small setting only until 1/2 of max_speed),
02277          * - in Chance16 - the last value is 512 / 2^smoke_amount (max. smoke when 128 = smoke_amount of 2). */
02278         int power_weight_effect = 0;
02279         if (v->type == VEH_TRAIN) {
02280           power_weight_effect = (32 >> (Train::From(this)->gcache.cached_power >> 10)) - (32 >> (Train::From(this)->gcache.cached_weight >> 9));
02281         }
02282         if (this->cur_speed < (this->vcache.cached_max_speed >> (2 >> _settings_game.vehicle.smoke_amount)) &&
02283             Chance16((64 - ((this->cur_speed << 5) / this->vcache.cached_max_speed) + power_weight_effect), (512 >> _settings_game.vehicle.smoke_amount))) {
02284           CreateEffectVehicleRel(v, x, y, 10, EV_DIESEL_SMOKE);
02285           sound = true;
02286         }
02287         break;
02288       }
02289 
02290       case VE_TYPE_ELECTRIC:
02291         /* Electric train's spark - more often occurs when train is departing (more load)
02292          * Details: Electric locomotives are usually at least twice as powerful as their diesel counterparts, so spark
02293          * emissions are kept simple. Only when starting, creating huge force are sparks more likely to happen, but when
02294          * reaching its max. speed, quarter by quarter of it, chance decreases untill the usuall 2,22% at train's top speed.
02295          * REGULATION:
02296          * - in Chance16 the last value is 360 / 2^smoke_amount (max. sparks when 90 = smoke_amount of 2). */
02297         if (GB(v->tick_counter, 0, 2) == 0 &&
02298             Chance16((6 - ((this->cur_speed << 2) / this->vcache.cached_max_speed)), (360 >> _settings_game.vehicle.smoke_amount))) {
02299           CreateEffectVehicleRel(v, x, y, 10, EV_ELECTRIC_SPARK);
02300           sound = true;
02301         }
02302         break;
02303 
02304       default:
02305         break;
02306     }
02307   } while ((v = v->Next()) != NULL);
02308 
02309   if (sound) PlayVehicleSound(this, VSE_VISUAL_EFFECT);
02310 }
02311 
02316 void Vehicle::SetNext(Vehicle *next)
02317 {
02318   assert(this != next);
02319 
02320   if (this->next != NULL) {
02321     /* We had an old next vehicle. Update the first and previous pointers */
02322     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
02323       v->first = this->next;
02324     }
02325     this->next->previous = NULL;
02326   }
02327 
02328   this->next = next;
02329 
02330   if (this->next != NULL) {
02331     /* A new next vehicle. Update the first and previous pointers */
02332     if (this->next->previous != NULL) this->next->previous->next = NULL;
02333     this->next->previous = this;
02334     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
02335       v->first = this->first;
02336     }
02337   }
02338 }
02339 
02345 void Vehicle::AddToShared(Vehicle *shared_chain)
02346 {
02347   assert(this->previous_shared == NULL && this->next_shared == NULL);
02348 
02349   if (shared_chain->orders.list == NULL) {
02350     assert(shared_chain->previous_shared == NULL);
02351     assert(shared_chain->next_shared == NULL);
02352     this->orders.list = shared_chain->orders.list = new OrderList(NULL, shared_chain);
02353   }
02354 
02355   this->next_shared     = shared_chain->next_shared;
02356   this->previous_shared = shared_chain;
02357 
02358   shared_chain->next_shared = this;
02359 
02360   if (this->next_shared != NULL) this->next_shared->previous_shared = this;
02361 
02362   shared_chain->orders.list->AddVehicle(this);
02363 }
02364 
02368 void Vehicle::RemoveFromShared()
02369 {
02370   /* Remember if we were first and the old window number before RemoveVehicle()
02371    * as this changes first if needed. */
02372   bool were_first = (this->FirstShared() == this);
02373   VehicleListIdentifier vli(VL_SHARED_ORDERS, this->type, this->owner, this->FirstShared()->index);
02374 
02375   this->orders.list->RemoveVehicle(this);
02376 
02377   if (!were_first) {
02378     /* We are not the first shared one, so only relink our previous one. */
02379     this->previous_shared->next_shared = this->NextShared();
02380   }
02381 
02382   if (this->next_shared != NULL) this->next_shared->previous_shared = this->previous_shared;
02383 
02384 
02385   if (this->orders.list->GetNumVehicles() == 1) {
02386     /* When there is only one vehicle, remove the shared order list window. */
02387     DeleteWindowById(GetWindowClassForVehicleType(this->type), vli.Pack());
02388     InvalidateVehicleOrder(this->FirstShared(), 0);
02389   } else if (were_first) {
02390     /* If we were the first one, update to the new first one.
02391      * Note: FirstShared() is already the new first */
02392     InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.Pack(), this->FirstShared()->index | (1U << 31));
02393   }
02394 
02395   this->next_shared     = NULL;
02396   this->previous_shared = NULL;
02397 }
02398 
02399 void VehiclesYearlyLoop()
02400 {
02401   Vehicle *v;
02402   FOR_ALL_VEHICLES(v) {
02403     if (v->IsPrimaryVehicle()) {
02404       /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
02405       Money profit = v->GetDisplayProfitThisYear();
02406       if (v->age >= 730 && profit < 0) {
02407         if (_settings_client.gui.vehicle_income_warn && v->owner == _local_company) {
02408           SetDParam(0, v->index);
02409           SetDParam(1, profit);
02410           AddVehicleNewsItem(
02411             STR_NEWS_VEHICLE_IS_UNPROFITABLE,
02412             NS_ADVICE,
02413             v->index
02414           );
02415         }
02416         AI::NewEvent(v->owner, new AIEventVehicleUnprofitable(v->index));
02417       }
02418 
02419       v->profit_last_year = v->profit_this_year;
02420       v->profit_this_year = 0;
02421       SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
02422     }
02423   }
02424 }
02425 
02426 
02436 bool CanVehicleUseStation(EngineID engine_type, const Station *st)
02437 {
02438   const Engine *e = Engine::GetIfValid(engine_type);
02439   assert(e != NULL);
02440 
02441   switch (e->type) {
02442     case VEH_TRAIN:
02443       return (st->facilities & FACIL_TRAIN) != 0;
02444 
02445     case VEH_ROAD:
02446       /* For road vehicles we need the vehicle to know whether it can actually
02447        * use the station, but if it doesn't have facilities for RVs it is
02448        * certainly not possible that the station can be used. */
02449       return (st->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP)) != 0;
02450 
02451     case VEH_SHIP:
02452       return (st->facilities & FACIL_DOCK) != 0;
02453 
02454     case VEH_AIRCRAFT:
02455       return (st->facilities & FACIL_AIRPORT) != 0 &&
02456           (st->airport.GetFTA()->flags & (e->u.air.subtype & AIR_CTOL ? AirportFTAClass::AIRPLANES : AirportFTAClass::HELICOPTERS)) != 0;
02457 
02458     default:
02459       return false;
02460   }
02461 }
02462 
02469 bool CanVehicleUseStation(const Vehicle *v, const Station *st)
02470 {
02471   if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != NULL;
02472 
02473   return CanVehicleUseStation(v->engine_type, st);
02474 }
02475 
02481 GroundVehicleCache *Vehicle::GetGroundVehicleCache()
02482 {
02483   assert(this->IsGroundVehicle());
02484   if (this->type == VEH_TRAIN) {
02485     return &Train::From(this)->gcache;
02486   } else {
02487     return &RoadVehicle::From(this)->gcache;
02488   }
02489 }
02490 
02496 const GroundVehicleCache *Vehicle::GetGroundVehicleCache() const
02497 {
02498   assert(this->IsGroundVehicle());
02499   if (this->type == VEH_TRAIN) {
02500     return &Train::From(this)->gcache;
02501   } else {
02502     return &RoadVehicle::From(this)->gcache;
02503   }
02504 }
02505 
02511 uint16 &Vehicle::GetGroundVehicleFlags()
02512 {
02513   assert(this->IsGroundVehicle());
02514   if (this->type == VEH_TRAIN) {
02515     return Train::From(this)->gv_flags;
02516   } else {
02517     return RoadVehicle::From(this)->gv_flags;
02518   }
02519 }
02520 
02526 const uint16 &Vehicle::GetGroundVehicleFlags() const
02527 {
02528   assert(this->IsGroundVehicle());
02529   if (this->type == VEH_TRAIN) {
02530     return Train::From(this)->gv_flags;
02531   } else {
02532     return RoadVehicle::From(this)->gv_flags;
02533   }
02534 }
02535 
02544 void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8 num_vehicles)
02545 {
02546   if (v->type == VEH_TRAIN) {
02547     Train *u = Train::From(v);
02548     /* Only include whole vehicles, so start with the first articulated part */
02549     u = u->GetFirstEnginePart();
02550 
02551     /* Include num_vehicles vehicles, not counting articulated parts */
02552     for (; u != NULL && num_vehicles > 0; num_vehicles--) {
02553       do {
02554         /* Include current vehicle in the selection. */
02555         set.Include(u->index);
02556 
02557         /* If the vehicle is multiheaded, add the other part too. */
02558         if (u->IsMultiheaded()) set.Include(u->other_multiheaded_part->index);
02559 
02560         u = u->Next();
02561       } while (u != NULL && u->IsArticulatedPart());
02562     }
02563   }
02564 }

Generated on Sun May 8 07:30:22 2011 for OpenTTD by  doxygen 1.6.1