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

Generated on Sun Jun 5 04:20:06 2011 for OpenTTD by  doxygen 1.6.1