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

Generated on Fri May 27 04:19:52 2011 for OpenTTD by  doxygen 1.6.1