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 "functions.h"
00033 #include "date_func.h"
00034 #include "window_func.h"
00035 #include "vehicle_func.h"
00036 #include "autoreplace_func.h"
00037 #include "autoreplace_gui.h"
00038 #include "station_base.h"
00039 #include "ai/ai.hpp"
00040 #include "depot_func.h"
00041 #include "network/network.h"
00042 #include "core/pool_func.hpp"
00043 #include "economy_base.h"
00044 #include "articulated_vehicles.h"
00045 #include "roadstop_base.h"
00046 #include "core/random_func.hpp"
00047 #include "core/backup_type.hpp"
00048 #include "order_backup.h"
00049 #include "sound_func.h"
00050 #include "effectvehicle_func.h"
00051 #include "effectvehicle_base.h"
00052 #include "vehiclelist.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 
00066 /* Initialize the vehicle-pool */
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 (_settings_game.order.gotodepot && 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   _vehicle_pool.CleanPool();
00590   _cargo_payment_pool.CleanPool();
00591 
00592   _age_cargo_skip_counter = 1;
00593 
00594   _vehicles_to_autoreplace.Reset();
00595   ResetVehiclePosHash();
00596 }
00597 
00598 uint CountVehiclesInChain(const Vehicle *v)
00599 {
00600   uint count = 0;
00601   do count++; while ((v = v->Next()) != NULL);
00602   return count;
00603 }
00604 
00610 void CountCompanyVehicles(CompanyID cid, uint counts[4])
00611 {
00612   for (uint i = 0; i < 4; i++) counts[i] = 0;
00613 
00614   const Vehicle *v;
00615   FOR_ALL_VEHICLES(v) {
00616     if (v->owner == cid && v->IsPrimaryVehicle()) counts[v->type]++;
00617   }
00618 }
00619 
00624 bool Vehicle::IsEngineCountable() const
00625 {
00626   switch (this->type) {
00627     case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft(); // don't count plane shadows and helicopter rotors
00628     case VEH_TRAIN:
00629       return !Train::From(this)->IsArticulatedPart() && // tenders and other articulated parts
00630           !Train::From(this)->IsRearDualheaded(); // rear parts of multiheaded engines
00631     case VEH_ROAD: return RoadVehicle::From(this)->IsFrontEngine();
00632     case VEH_SHIP: return true;
00633     default: return false; // Only count company buildable vehicles
00634   }
00635 }
00636 
00644 void Vehicle::HandlePathfindingResult(bool path_found)
00645 {
00646   if (path_found) {
00647     /* Route found, is the vehicle marked with "lost" flag? */
00648     if (!HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;
00649 
00650     /* Clear the flag as the PF's problem was solved. */
00651     ClrBit(this->vehicle_flags, VF_PATHFINDER_LOST);
00652     /* Delete the news item. */
00653     DeleteVehicleNews(this->index, STR_NEWS_VEHICLE_IS_LOST);
00654     return;
00655   }
00656 
00657   /* Were we already lost? */
00658   if (HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;
00659 
00660   /* It is first time the problem occurred, set the "lost" flag. */
00661   SetBit(this->vehicle_flags, VF_PATHFINDER_LOST);
00662   /* Notify user about the event. */
00663   AI::NewEvent(this->owner, new AIEventVehicleLost(this->index));
00664   if (_settings_client.gui.lost_vehicle_warn && this->owner == _local_company) {
00665     SetDParam(0, this->index);
00666     AddVehicleNewsItem(STR_NEWS_VEHICLE_IS_LOST, NS_ADVICE, this->index);
00667   }
00668 }
00669 
00671 void Vehicle::PreDestructor()
00672 {
00673   if (CleaningPool()) return;
00674 
00675   if (Station::IsValidID(this->last_station_visited)) {
00676     Station::Get(this->last_station_visited)->loading_vehicles.remove(this);
00677 
00678     HideFillingPercent(&this->fill_percent_te_id);
00679 
00680     delete this->cargo_payment;
00681   }
00682 
00683   if (this->IsEngineCountable()) {
00684     Company::Get(this->owner)->num_engines[this->engine_type]--;
00685     if (this->owner == _local_company) InvalidateAutoreplaceWindow(this->engine_type, this->group_id);
00686 
00687     DeleteGroupHighlightOfVehicle(this);
00688     if (Group::IsValidID(this->group_id)) Group::Get(this->group_id)->num_engines[this->engine_type]--;
00689     if (this->IsPrimaryVehicle()) DecreaseGroupNumVehicle(this->group_id);
00690   }
00691 
00692   if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) {
00693     Aircraft *a = Aircraft::From(this);
00694     Station *st = GetTargetAirportIfValid(a);
00695     if (st != NULL) {
00696       const AirportFTA *layout = st->airport.GetFTA()->layout;
00697       CLRBITS(st->airport.flags, layout[a->previous_pos].block | layout[a->pos].block);
00698     }
00699   }
00700 
00701 
00702   if (this->type == VEH_ROAD && this->IsPrimaryVehicle()) {
00703     RoadVehicle *v = RoadVehicle::From(this);
00704     if (!(v->vehstatus & VS_CRASHED) && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
00705       /* Leave the drive through roadstop, when you have not already left it. */
00706       RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
00707     }
00708   }
00709 
00710   if (this->Previous() == NULL) {
00711     InvalidateWindowData(WC_VEHICLE_DEPOT, this->tile);
00712   }
00713 
00714   if (this->IsPrimaryVehicle()) {
00715     DeleteWindowById(WC_VEHICLE_VIEW, this->index);
00716     DeleteWindowById(WC_VEHICLE_ORDERS, this->index);
00717     DeleteWindowById(WC_VEHICLE_REFIT, this->index);
00718     DeleteWindowById(WC_VEHICLE_DETAILS, this->index);
00719     DeleteWindowById(WC_VEHICLE_TIMETABLE, this->index);
00720     SetWindowDirty(WC_COMPANY, this->owner);
00721     OrderBackup::ClearVehicle(this);
00722   }
00723   InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
00724 
00725   this->cargo.Truncate(0);
00726   DeleteVehicleOrders(this);
00727   DeleteDepotHighlightOfVehicle(this);
00728 
00729   extern void StopGlobalFollowVehicle(const Vehicle *v);
00730   StopGlobalFollowVehicle(this);
00731 
00732   ReleaseDisastersTargetingVehicle(this->index);
00733 }
00734 
00735 Vehicle::~Vehicle()
00736 {
00737   free(this->name);
00738 
00739   if (CleaningPool()) return;
00740 
00741   /* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles,
00742    * it may happen that vehicle chain is deleted when visible */
00743   if (!(this->vehstatus & VS_HIDDEN)) MarkSingleVehicleDirty(this);
00744 
00745   Vehicle *v = this->Next();
00746   this->SetNext(NULL);
00747 
00748   delete v;
00749 
00750   UpdateVehiclePosHash(this, INVALID_COORD, 0);
00751   DeleteVehicleNews(this->index, INVALID_STRING_ID);
00752   DeleteNewGRFInspectWindow(GetGrfSpecFeature(this->type), this->index);
00753 }
00754 
00759 void VehicleEnteredDepotThisTick(Vehicle *v)
00760 {
00761   /* Vehicle should stop in the depot if it was in 'stopping' state */
00762   _vehicles_to_autoreplace[v] = !(v->vehstatus & VS_STOPPED);
00763 
00764   /* We ALWAYS set the stopped state. Even when the vehicle does not plan on
00765    * stopping in the depot, so we stop it to ensure that it will not reserve
00766    * the path out of the depot before we might autoreplace it to a different
00767    * engine. The new engine would not own the reserved path we store that we
00768    * stopped the vehicle, so autoreplace can start it again */
00769   v->vehstatus |= VS_STOPPED;
00770 }
00771 
00777 static void RunVehicleDayProc()
00778 {
00779   if (_game_mode != GM_NORMAL) return;
00780 
00781   /* Run the day_proc for every DAY_TICKS vehicle starting at _date_fract. */
00782   for (size_t i = _date_fract; i < Vehicle::GetPoolSize(); i += DAY_TICKS) {
00783     Vehicle *v = Vehicle::Get(i);
00784     if (v == NULL) continue;
00785 
00786     /* Call the 32-day callback if needed */
00787     if ((v->day_counter & 0x1F) == 0) {
00788       uint16 callback = GetVehicleCallback(CBID_VEHICLE_32DAY_CALLBACK, 0, 0, v->engine_type, v);
00789       if (callback != CALLBACK_FAILED) {
00790         if (HasBit(callback, 0)) TriggerVehicle(v, VEHICLE_TRIGGER_CALLBACK_32); // Trigger vehicle trigger 10
00791         if (HasBit(callback, 1)) v->colourmap = PAL_NONE;
00792       }
00793     }
00794 
00795     /* This is called once per day for each vehicle, but not in the first tick of the day */
00796     v->OnNewDay();
00797   }
00798 }
00799 
00800 void CallVehicleTicks()
00801 {
00802   _vehicles_to_autoreplace.Clear();
00803 
00804   _age_cargo_skip_counter = (_age_cargo_skip_counter == 0) ? 184 : (_age_cargo_skip_counter - 1);
00805 
00806   RunVehicleDayProc();
00807 
00808   Station *st;
00809   FOR_ALL_STATIONS(st) LoadUnloadStation(st);
00810 
00811   Vehicle *v;
00812   FOR_ALL_VEHICLES(v) {
00813     /* Vehicle could be deleted in this tick */
00814     if (!v->Tick()) {
00815       assert(Vehicle::Get(vehicle_index) == NULL);
00816       continue;
00817     }
00818 
00819     assert(Vehicle::Get(vehicle_index) == v);
00820 
00821     switch (v->type) {
00822       default: break;
00823 
00824       case VEH_TRAIN:
00825       case VEH_ROAD:
00826       case VEH_AIRCRAFT:
00827       case VEH_SHIP:
00828         if (_age_cargo_skip_counter == 0) v->cargo.AgeCargo();
00829 
00830         if (v->type == VEH_TRAIN && Train::From(v)->IsWagon()) continue;
00831         if (v->type == VEH_AIRCRAFT && v->subtype != AIR_HELICOPTER) continue;
00832         if (v->type == VEH_ROAD && !RoadVehicle::From(v)->IsFrontEngine()) continue;
00833 
00834         v->motion_counter += v->cur_speed;
00835         /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
00836         if (GB(v->motion_counter, 0, 8) < v->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
00837 
00838         /* Play an alterate running sound every 16 ticks */
00839         if (GB(v->tick_counter, 0, 4) == 0) PlayVehicleSound(v, v->cur_speed > 0 ? VSE_RUNNING_16 : VSE_STOPPED_16);
00840     }
00841   }
00842 
00843   Backup<CompanyByte> cur_company(_current_company, FILE_LINE);
00844   for (AutoreplaceMap::iterator it = _vehicles_to_autoreplace.Begin(); it != _vehicles_to_autoreplace.End(); it++) {
00845     v = it->first;
00846     /* Autoreplace needs the current company set as the vehicle owner */
00847     cur_company.Change(v->owner);
00848 
00849     /* Start vehicle if we stopped them in VehicleEnteredDepotThisTick()
00850      * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that
00851      * they are already leaving the depot again before being replaced. */
00852     if (it->second) v->vehstatus &= ~VS_STOPPED;
00853 
00854     /* Store the position of the effect as the vehicle pointer will become invalid later */
00855     int x = v->x_pos;
00856     int y = v->y_pos;
00857     int z = v->z_pos;
00858 
00859     const Company *c = Company::Get(_current_company);
00860     SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, (Money)c->settings.engine_renew_money));
00861     CommandCost res = DoCommand(0, v->index, 0, DC_EXEC, CMD_AUTOREPLACE_VEHICLE);
00862     SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, -(Money)c->settings.engine_renew_money));
00863 
00864     if (!IsLocalCompany()) continue;
00865 
00866     if (res.Succeeded()) {
00867       ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
00868       continue;
00869     }
00870 
00871     StringID error_message = res.GetErrorMessage();
00872     if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message == INVALID_STRING_ID) continue;
00873 
00874     if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT;
00875 
00876     StringID message;
00877     if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
00878       message = error_message;
00879     } else {
00880       message = STR_NEWS_VEHICLE_AUTORENEW_FAILED;
00881     }
00882 
00883     SetDParam(0, v->index);
00884     SetDParam(1, error_message);
00885     AddVehicleNewsItem(message, NS_ADVICE, v->index);
00886   }
00887 
00888   cur_company.Restore();
00889 }
00890 
00895 static void DoDrawVehicle(const Vehicle *v)
00896 {
00897   SpriteID image = v->cur_image;
00898   PaletteID pal = PAL_NONE;
00899 
00900   if (v->vehstatus & VS_DEFPAL) pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
00901   if ((v->vehstatus & VS_SHADOW) != 0)
00902   {
00903     SetBit(image, PALETTE_MODIFIER_SHADOW);
00904   }
00905   AddSortableSpriteToDraw(image, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
00906     v->x_extent, v->y_extent, v->z_extent, v->z_pos, false);
00907 }
00908 
00909 void ViewportAddVehicles(DrawPixelInfo *dpi)
00910 {
00911   /* The bounding rectangle */
00912   const int l = dpi->left;
00913   const int r = dpi->left + dpi->width;
00914   const int t = dpi->top;
00915   const int b = dpi->top + dpi->height;
00916 
00917   /* The hash area to scan */
00918   int xl, xu, yl, yu;
00919 
00920   if (dpi->width + 70 < (1 << (7 + 6))) {
00921     xl = GB(l - 70, 7, 6);
00922     xu = GB(r,      7, 6);
00923   } else {
00924     /* scan whole hash row */
00925     xl = 0;
00926     xu = 0x3F;
00927   }
00928 
00929   if (dpi->height + 70 < (1 << (6 + 6))) {
00930     yl = GB(t - 70, 6, 6) << 6;
00931     yu = GB(b,      6, 6) << 6;
00932   } else {
00933     /* scan whole column */
00934     yl = 0;
00935     yu = 0x3F << 6;
00936   }
00937 
00938   for (int y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
00939     for (int x = xl;; x = (x + 1) & 0x3F) {
00940       const Vehicle *v = _vehicle_position_hash[x + y]; // already masked & 0xFFF
00941 
00942       while (v != NULL) {
00943         if (!(v->vehstatus & VS_HIDDEN) ) {
00944           DoDrawVehicle(v);
00945         }
00946         v = v->next_hash;
00947       }
00948 
00949       if (x == xu) break;
00950     }
00951 
00952     if (y == yu) break;
00953   }
00954 }
00955 
00956 Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y)
00957 {
00958   Vehicle *found = NULL, *v;
00959   uint dist, best_dist = UINT_MAX;
00960 
00961   if ((uint)(x -= vp->left) >= (uint)vp->width || (uint)(y -= vp->top) >= (uint)vp->height) return NULL;
00962 
00963   x = ScaleByZoom(x + vp->virtual_left, vp->zoom);
00964   y = ScaleByZoom(y + vp->virtual_top, vp->zoom) ;
00965 
00966   FOR_ALL_VEHICLES(v) {
00967     if ((v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0 &&
00968         x >= v->coord.left && x <= v->coord.right &&
00969         y >= v->coord.top && y <= v->coord.bottom) {
00970 
00971       dist = max(
00972         abs(((v->coord.left + v->coord.right) >> 1) - x),
00973         abs(((v->coord.top + v->coord.bottom) >> 1) - y)
00974       );
00975 
00976       if (dist < best_dist) {
00977         found = v;
00978         best_dist = dist;
00979       }
00980     }
00981   }
00982 
00983   return found;
00984 }
00985 
00986 void DecreaseVehicleValue(Vehicle *v)
00987 {
00988   v->value -= v->value >> 8;
00989   SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
00990 }
00991 
00992 static const byte _breakdown_chance[64] = {
00993     3,   3,   3,   3,   3,   3,   3,   3,
00994     4,   4,   5,   5,   6,   6,   7,   7,
00995     8,   8,   9,   9,  10,  10,  11,  11,
00996    12,  13,  13,  13,  13,  14,  15,  16,
00997    17,  19,  21,  25,  28,  31,  34,  37,
00998    40,  44,  48,  52,  56,  60,  64,  68,
00999    72,  80,  90, 100, 110, 120, 130, 140,
01000   150, 170, 190, 210, 230, 250, 250, 250,
01001 };
01002 
01003 void CheckVehicleBreakdown(Vehicle *v)
01004 {
01005   int rel, rel_old;
01006 
01007   /* decrease reliability */
01008   v->reliability = rel = max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
01009   if ((rel_old >> 8) != (rel >> 8)) SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
01010 
01011   if (v->breakdown_ctr != 0 || (v->vehstatus & VS_STOPPED) ||
01012       _settings_game.difficulty.vehicle_breakdowns < 1 ||
01013       v->cur_speed < 5 || _game_mode == GM_MENU) {
01014     return;
01015   }
01016 
01017   uint32 r = Random();
01018 
01019   /* increase chance of failure */
01020   int chance = v->breakdown_chance + 1;
01021   if (Chance16I(1, 25, r)) chance += 25;
01022   v->breakdown_chance = min(255, chance);
01023 
01024   /* calculate reliability value to use in comparison */
01025   rel = v->reliability;
01026   if (v->type == VEH_SHIP) rel += 0x6666;
01027 
01028   /* reduced breakdowns? */
01029   if (_settings_game.difficulty.vehicle_breakdowns == 1) rel += 0x6666;
01030 
01031   /* check if to break down */
01032   if (_breakdown_chance[(uint)min(rel, 0xffff) >> 10] <= v->breakdown_chance) {
01033     v->breakdown_ctr    = GB(r, 16, 6) + 0x3F;
01034     v->breakdown_delay  = GB(r, 24, 7) + 0x80;
01035     v->breakdown_chance = 0;
01036   }
01037 }
01038 
01045 bool Vehicle::HandleBreakdown()
01046 {
01047   /* Possible states for Vehicle::breakdown_ctr
01048    * 0  - vehicle is running normally
01049    * 1  - vehicle is currently broken down
01050    * 2  - vehicle is going to break down now
01051    * >2 - vehicle is counting down to the actual breakdown event */
01052   switch (this->breakdown_ctr) {
01053     case 0:
01054       return false;
01055 
01056     case 2:
01057       this->breakdown_ctr = 1;
01058 
01059       if (this->breakdowns_since_last_service != 255) {
01060         this->breakdowns_since_last_service++;
01061       }
01062 
01063       this->MarkDirty();
01064       SetWindowDirty(WC_VEHICLE_VIEW, this->index);
01065       SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
01066 
01067       if (this->type == VEH_AIRCRAFT) {
01068         /* Aircraft just need this flag, the rest is handled elsewhere */
01069         this->vehstatus |= VS_AIRCRAFT_BROKEN;
01070       } else {
01071         this->cur_speed = 0;
01072 
01073         if (!PlayVehicleSound(this, VSE_BREAKDOWN)) {
01074           SndPlayVehicleFx((_settings_game.game_creation.landscape != LT_TOYLAND) ?
01075             (this->type == VEH_TRAIN ? SND_10_TRAIN_BREAKDOWN : SND_0F_VEHICLE_BREAKDOWN) :
01076             (this->type == VEH_TRAIN ? SND_3A_COMEDY_BREAKDOWN_2 : SND_35_COMEDY_BREAKDOWN), this);
01077         }
01078 
01079         if (!(this->vehstatus & VS_HIDDEN)) {
01080           EffectVehicle *u = CreateEffectVehicleRel(this, 4, 4, 5, EV_BREAKDOWN_SMOKE);
01081           if (u != NULL) u->animation_state = this->breakdown_delay * 2;
01082         }
01083       }
01084       /* FALL THROUGH */
01085     case 1:
01086       /* Aircraft breakdowns end only when arriving at the airport */
01087       if (this->type == VEH_AIRCRAFT) return false;
01088 
01089       /* For trains this function is called twice per tick, so decrease v->breakdown_delay at half the rate */
01090       if ((this->tick_counter & (this->type == VEH_TRAIN ? 3 : 1)) == 0) {
01091         if (--this->breakdown_delay == 0) {
01092           this->breakdown_ctr = 0;
01093           this->MarkDirty();
01094           SetWindowDirty(WC_VEHICLE_VIEW, this->index);
01095         }
01096       }
01097       return true;
01098 
01099     default:
01100       if (!this->current_order.IsType(OT_LOADING)) this->breakdown_ctr--;
01101       return false;
01102   }
01103 }
01104 
01109 void AgeVehicle(Vehicle *v)
01110 {
01111   if (v->age < MAX_DAY) v->age++;
01112 
01113   int age = v->age - v->max_age;
01114   if (age == DAYS_IN_LEAP_YEAR * 0 || age == DAYS_IN_LEAP_YEAR * 1 ||
01115       age == DAYS_IN_LEAP_YEAR * 2 || age == DAYS_IN_LEAP_YEAR * 3 || age == DAYS_IN_LEAP_YEAR * 4) {
01116     v->reliability_spd_dec <<= 1;
01117   }
01118 
01119   SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
01120 
01121   /* Don't warn about non-primary or not ours vehicles or vehicles that are crashed */
01122   if (v->Previous() != NULL || v->owner != _local_company || (v->vehstatus & VS_CRASHED) != 0) return;
01123 
01124   /* Don't warn if a renew is active */
01125   if (Company::Get(v->owner)->settings.engine_renew && Engine::Get(v->engine_type)->company_avail != 0) return;
01126 
01127   StringID str;
01128   if (age == -DAYS_IN_LEAP_YEAR) {
01129     str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
01130   } else if (age == 0) {
01131     str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
01132   } else if (age > 0 && (age % DAYS_IN_LEAP_YEAR) == 0) {
01133     str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
01134   } else {
01135     return;
01136   }
01137 
01138   SetDParam(0, v->index);
01139   AddVehicleNewsItem(str, NS_ADVICE, v->index);
01140 }
01141 
01148 uint8 CalcPercentVehicleFilled(const Vehicle *v, StringID *colour)
01149 {
01150   int count = 0;
01151   int max = 0;
01152   int cars = 0;
01153   int unloading = 0;
01154   bool loading = false;
01155 
01156   const Vehicle *u = v;
01157   /* The station may be NULL when the (colour) string does not need to be set. */
01158   const Station *st = Station::GetIfValid(v->last_station_visited);
01159   assert(colour == NULL || st != NULL);
01160 
01161   /* Count up max and used */
01162   for (; v != NULL; v = v->Next()) {
01163     count += v->cargo.Count();
01164     max += v->cargo_cap;
01165     if (v->cargo_cap != 0 && colour != NULL) {
01166       unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0;
01167       loading |= !(u->current_order.GetLoadType() & OLFB_NO_LOAD) && st->goods[v->cargo_type].days_since_pickup != 255;
01168       cars++;
01169     }
01170   }
01171 
01172   if (colour != NULL) {
01173     if (unloading == 0 && loading) {
01174       *colour = STR_PERCENT_UP;
01175     } else if (cars == unloading || !loading) {
01176       *colour = STR_PERCENT_DOWN;
01177     } else {
01178       *colour = STR_PERCENT_UP_DOWN;
01179     }
01180   }
01181 
01182   /* Train without capacity */
01183   if (max == 0) return 100;
01184 
01185   /* Return the percentage */
01186   return (count * 100) / max;
01187 }
01188 
01189 void VehicleEnterDepot(Vehicle *v)
01190 {
01191   /* Always work with the front of the vehicle */
01192   assert(v == v->First());
01193 
01194   switch (v->type) {
01195     case VEH_TRAIN: {
01196       Train *t = Train::From(v);
01197       SetWindowClassesDirty(WC_TRAINS_LIST);
01198       /* Clear path reservation */
01199       SetDepotReservation(t->tile, false);
01200       if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(t->tile);
01201 
01202       UpdateSignalsOnSegment(t->tile, INVALID_DIAGDIR, t->owner);
01203       t->wait_counter = 0;
01204       t->force_proceed = TFP_NONE;
01205       ClrBit(t->flags, VRF_TOGGLE_REVERSE);
01206       t->ConsistChanged(true);
01207       break;
01208     }
01209 
01210     case VEH_ROAD:
01211       SetWindowClassesDirty(WC_ROADVEH_LIST);
01212       break;
01213 
01214     case VEH_SHIP: {
01215       SetWindowClassesDirty(WC_SHIPS_LIST);
01216       Ship *ship = Ship::From(v);
01217       ship->state = TRACK_BIT_DEPOT;
01218       ship->UpdateCache();
01219       ship->UpdateViewport(true, true);
01220       SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
01221       break;
01222     }
01223 
01224     case VEH_AIRCRAFT:
01225       SetWindowClassesDirty(WC_AIRCRAFT_LIST);
01226       HandleAircraftEnterHangar(Aircraft::From(v));
01227       break;
01228     default: NOT_REACHED();
01229   }
01230   SetWindowDirty(WC_VEHICLE_VIEW, v->index);
01231 
01232   if (v->type != VEH_TRAIN) {
01233     /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
01234      * 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 */
01235     InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
01236   }
01237   SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
01238 
01239   v->vehstatus |= VS_HIDDEN;
01240   v->cur_speed = 0;
01241 
01242   VehicleServiceInDepot(v);
01243 
01244   TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
01245 
01246   if (v->current_order.IsType(OT_GOTO_DEPOT)) {
01247     SetWindowDirty(WC_VEHICLE_VIEW, v->index);
01248 
01249     const Order *real_order = v->GetNextManualOrder(v->cur_order_index);
01250     Order t = v->current_order;
01251     v->current_order.MakeDummy();
01252 
01253     /* Test whether we are heading for this depot. If not, do nothing.
01254      * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
01255     if ((t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) &&
01256         real_order != NULL && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) &&
01257         (v->type == VEH_AIRCRAFT ? t.GetDestination() != GetStationIndex(v->tile) : v->dest_tile != v->tile)) {
01258       /* We are heading for another depot, keep driving. */
01259       return;
01260     }
01261 
01262     if (t.IsRefit()) {
01263       Backup<CompanyByte> cur_company(_current_company, v->owner, FILE_LINE);
01264       CommandCost cost = DoCommand(v->tile, v->index, t.GetRefitCargo() | t.GetRefitSubtype() << 8, DC_EXEC, GetCmdRefitVeh(v));
01265       cur_company.Restore();
01266 
01267       if (cost.Failed()) {
01268         _vehicles_to_autoreplace[v] = false;
01269         if (v->owner == _local_company) {
01270           /* Notify the user that we stopped the vehicle */
01271           SetDParam(0, v->index);
01272           AddVehicleNewsItem(STR_NEWS_ORDER_REFIT_FAILED, NS_ADVICE, v->index);
01273         }
01274       } else if (cost.GetCost() != 0) {
01275         v->profit_this_year -= cost.GetCost() << 8;
01276         if (v->owner == _local_company) {
01277           ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
01278         }
01279       }
01280     }
01281 
01282     if (t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
01283       /* Part of orders */
01284       v->DeleteUnreachedAutoOrders();
01285       UpdateVehicleTimetable(v, true);
01286       v->IncrementOrderIndex();
01287     }
01288     if (t.GetDepotActionType() & ODATFB_HALT) {
01289       /* Vehicles are always stopped on entering depots. Do not restart this one. */
01290       _vehicles_to_autoreplace[v] = false;
01291       if (v->owner == _local_company) {
01292         SetDParam(0, v->index);
01293         AddVehicleNewsItem(STR_NEWS_TRAIN_IS_WAITING + v->type, NS_ADVICE, v->index);
01294       }
01295       AI::NewEvent(v->owner, new AIEventVehicleWaitingInDepot(v->index));
01296     }
01297   }
01298 }
01299 
01300 
01308 void VehicleMove(Vehicle *v, bool update_viewport)
01309 {
01310   int img = v->cur_image;
01311   Point pt = RemapCoords(v->x_pos + v->x_offs, v->y_pos + v->y_offs, v->z_pos);
01312   const Sprite *spr = GetSprite(img, ST_NORMAL);
01313 
01314   pt.x += spr->x_offs;
01315   pt.y += spr->y_offs;
01316 
01317   UpdateVehiclePosHash(v, pt.x, pt.y);
01318 
01319   Rect old_coord = v->coord;
01320   v->coord.left   = pt.x;
01321   v->coord.top    = pt.y;
01322   v->coord.right  = pt.x + spr->width + 2;
01323   v->coord.bottom = pt.y + spr->height + 2;
01324 
01325   if (update_viewport) {
01326     MarkAllViewportsDirty(
01327       min(old_coord.left,   v->coord.left),
01328       min(old_coord.top,    v->coord.top),
01329       max(old_coord.right,  v->coord.right) + 1,
01330       max(old_coord.bottom, v->coord.bottom) + 1
01331     );
01332   }
01333 }
01334 
01343 void MarkSingleVehicleDirty(const Vehicle *v)
01344 {
01345   MarkAllViewportsDirty(v->coord.left, v->coord.top, v->coord.right + 1, v->coord.bottom + 1);
01346 }
01347 
01353 GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
01354 {
01355   static const int8 _delta_coord[16] = {
01356     -1,-1,-1, 0, 1, 1, 1, 0, /* x */
01357     -1, 0, 1, 1, 1, 0,-1,-1, /* y */
01358   };
01359 
01360   int x = v->x_pos + _delta_coord[v->direction];
01361   int y = v->y_pos + _delta_coord[v->direction + 8];
01362 
01363   GetNewVehiclePosResult gp;
01364   gp.x = x;
01365   gp.y = y;
01366   gp.old_tile = v->tile;
01367   gp.new_tile = TileVirtXY(x, y);
01368   return gp;
01369 }
01370 
01371 static const Direction _new_direction_table[] = {
01372   DIR_N,  DIR_NW, DIR_W,
01373   DIR_NE, DIR_SE, DIR_SW,
01374   DIR_E,  DIR_SE, DIR_S
01375 };
01376 
01377 Direction GetDirectionTowards(const Vehicle *v, int x, int y)
01378 {
01379   int i = 0;
01380 
01381   if (y >= v->y_pos) {
01382     if (y != v->y_pos) i += 3;
01383     i += 3;
01384   }
01385 
01386   if (x >= v->x_pos) {
01387     if (x != v->x_pos) i++;
01388     i++;
01389   }
01390 
01391   Direction dir = v->direction;
01392 
01393   DirDiff dirdiff = DirDifference(_new_direction_table[i], dir);
01394   if (dirdiff == DIRDIFF_SAME) return dir;
01395   return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
01396 }
01397 
01407 VehicleEnterTileStatus VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
01408 {
01409   return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
01410 }
01411 
01419 FreeUnitIDGenerator::FreeUnitIDGenerator(VehicleType type, CompanyID owner) : cache(NULL), maxid(0), curid(0)
01420 {
01421   /* Find maximum */
01422   const Vehicle *v;
01423   FOR_ALL_VEHICLES(v) {
01424     if (v->type == type && v->owner == owner) {
01425       this->maxid = max<UnitID>(this->maxid, v->unitnumber);
01426     }
01427   }
01428 
01429   if (this->maxid == 0) return;
01430 
01431   /* Reserving 'maxid + 2' because we need:
01432    * - space for the last item (with v->unitnumber == maxid)
01433    * - one free slot working as loop terminator in FreeUnitIDGenerator::NextID() */
01434   this->cache = CallocT<bool>(this->maxid + 2);
01435 
01436   /* Fill the cache */
01437   FOR_ALL_VEHICLES(v) {
01438     if (v->type == type && v->owner == owner) {
01439       this->cache[v->unitnumber] = true;
01440     }
01441   }
01442 }
01443 
01445 UnitID FreeUnitIDGenerator::NextID()
01446 {
01447   if (this->maxid <= this->curid) return ++this->curid;
01448 
01449   while (this->cache[++this->curid]) { } // it will stop, we reserved more space than needed
01450 
01451   return this->curid;
01452 }
01453 
01459 UnitID GetFreeUnitNumber(VehicleType type)
01460 {
01461   /* Check whether it is allowed to build another vehicle. */
01462   uint max_veh;
01463   switch (type) {
01464     case VEH_TRAIN:    max_veh = _settings_game.vehicle.max_trains;   break;
01465     case VEH_ROAD:     max_veh = _settings_game.vehicle.max_roadveh;  break;
01466     case VEH_SHIP:     max_veh = _settings_game.vehicle.max_ships;    break;
01467     case VEH_AIRCRAFT: max_veh = _settings_game.vehicle.max_aircraft; break;
01468     default: NOT_REACHED();
01469   }
01470 
01471   uint amounts[4];
01472   CountCompanyVehicles(_current_company, amounts);
01473   assert((uint)type < lengthof(amounts));
01474   if (amounts[type] >= max_veh) return UINT16_MAX; // Currently already at the limit, no room to make a new one.
01475 
01476   FreeUnitIDGenerator gen(type, _current_company);
01477 
01478   return gen.NextID();
01479 }
01480 
01481 
01490 bool CanBuildVehicleInfrastructure(VehicleType type)
01491 {
01492   assert(IsCompanyBuildableVehicleType(type));
01493 
01494   if (!Company::IsValidID(_local_company)) return false;
01495   if (!_settings_client.gui.disable_unsuitable_building) return true;
01496 
01497   UnitID max;
01498   switch (type) {
01499     case VEH_TRAIN:    max = _settings_game.vehicle.max_trains; break;
01500     case VEH_ROAD:     max = _settings_game.vehicle.max_roadveh; break;
01501     case VEH_SHIP:     max = _settings_game.vehicle.max_ships; break;
01502     case VEH_AIRCRAFT: max = _settings_game.vehicle.max_aircraft; break;
01503     default: NOT_REACHED();
01504   }
01505 
01506   /* We can build vehicle infrastructure when we may build the vehicle type */
01507   if (max > 0) {
01508     /* Can we actually build the vehicle type? */
01509     const Engine *e;
01510     FOR_ALL_ENGINES_OF_TYPE(e, type) {
01511       if (HasBit(e->company_avail, _local_company)) return true;
01512     }
01513     return false;
01514   }
01515 
01516   /* We should be able to build infrastructure when we have the actual vehicle type */
01517   const Vehicle *v;
01518   FOR_ALL_VEHICLES(v) {
01519     if (v->owner == _local_company && v->type == type) return true;
01520   }
01521 
01522   return false;
01523 }
01524 
01525 
01533 LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
01534 {
01535   CargoID cargo_type = v == NULL ? (CargoID)CT_INVALID : v->cargo_type;
01536   const Engine *e = Engine::Get(engine_type);
01537   switch (e->type) {
01538     default: NOT_REACHED();
01539     case VEH_TRAIN:
01540       if (v != NULL && parent_engine_type != INVALID_ENGINE && (UsesWagonOverride(v) || (Train::From(v)->IsArticulatedPart() && e->u.rail.railveh_type != RAILVEH_WAGON))) {
01541         /* Wagonoverrides use the colour scheme of the front engine.
01542          * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */
01543         engine_type = parent_engine_type;
01544         e = Engine::Get(engine_type);
01545         /* Note: Luckily cargo_type is not needed for engines */
01546       }
01547 
01548       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
01549       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
01550       if (e->u.rail.railveh_type == RAILVEH_WAGON) {
01551         if (!CargoSpec::Get(cargo_type)->is_freight) {
01552           if (parent_engine_type == INVALID_ENGINE) {
01553             return LS_PASSENGER_WAGON_STEAM;
01554           } else {
01555             switch (RailVehInfo(parent_engine_type)->engclass) {
01556               default: NOT_REACHED();
01557               case EC_STEAM:    return LS_PASSENGER_WAGON_STEAM;
01558               case EC_DIESEL:   return LS_PASSENGER_WAGON_DIESEL;
01559               case EC_ELECTRIC: return LS_PASSENGER_WAGON_ELECTRIC;
01560               case EC_MONORAIL: return LS_PASSENGER_WAGON_MONORAIL;
01561               case EC_MAGLEV:   return LS_PASSENGER_WAGON_MAGLEV;
01562             }
01563           }
01564         } else {
01565           return LS_FREIGHT_WAGON;
01566         }
01567       } else {
01568         bool is_mu = HasBit(e->info.misc_flags, EF_RAIL_IS_MU);
01569 
01570         switch (e->u.rail.engclass) {
01571           default: NOT_REACHED();
01572           case EC_STEAM:    return LS_STEAM;
01573           case EC_DIESEL:   return is_mu ? LS_DMU : LS_DIESEL;
01574           case EC_ELECTRIC: return is_mu ? LS_EMU : LS_ELECTRIC;
01575           case EC_MONORAIL: return LS_MONORAIL;
01576           case EC_MAGLEV:   return LS_MAGLEV;
01577         }
01578       }
01579 
01580     case VEH_ROAD:
01581       /* Always use the livery of the front */
01582       if (v != NULL && parent_engine_type != INVALID_ENGINE) {
01583         engine_type = parent_engine_type;
01584         e = Engine::Get(engine_type);
01585         cargo_type = v->First()->cargo_type;
01586       }
01587       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
01588       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
01589 
01590       /* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */
01591       if (HasBit(e->info.misc_flags, EF_ROAD_TRAM)) {
01592         /* Tram */
01593         return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
01594       } else {
01595         /* Bus or truck */
01596         return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_BUS : LS_TRUCK;
01597       }
01598 
01599     case VEH_SHIP:
01600       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
01601       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
01602       return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
01603 
01604     case VEH_AIRCRAFT:
01605       switch (e->u.air.subtype) {
01606         case AIR_HELI: return LS_HELICOPTER;
01607         case AIR_CTOL: return LS_SMALL_PLANE;
01608         case AIR_CTOL | AIR_FAST: return LS_LARGE_PLANE;
01609         default: NOT_REACHED();
01610       }
01611   }
01612 }
01613 
01623 const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, byte livery_setting)
01624 {
01625   const Company *c = Company::Get(company);
01626   LiveryScheme scheme = LS_DEFAULT;
01627 
01628   /* The default livery is always available for use, but its in_use flag determines
01629    * whether any _other_ liveries are in use. */
01630   if (c->livery[LS_DEFAULT].in_use && (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company))) {
01631     /* Determine the livery scheme to use */
01632     scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
01633 
01634     /* Switch back to the default scheme if the resolved scheme is not in use */
01635     if (!c->livery[scheme].in_use) scheme = LS_DEFAULT;
01636   }
01637 
01638   return &c->livery[scheme];
01639 }
01640 
01641 
01642 static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
01643 {
01644   PaletteID map = (v != NULL) ? v->colourmap : PAL_NONE;
01645 
01646   /* Return cached value if any */
01647   if (map != PAL_NONE) return map;
01648 
01649   const Engine *e = Engine::Get(engine_type);
01650 
01651   /* Check if we should use the colour map callback */
01652   if (HasBit(e->info.callback_mask, CBM_VEHICLE_COLOUR_REMAP)) {
01653     uint16 callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
01654     /* Failure means "use the default two-colour" */
01655     if (callback != CALLBACK_FAILED) {
01656       assert_compile(PAL_NONE == 0); // Returning 0x4000 (resp. 0xC000) conincidences with default value (PAL_NONE)
01657       map = GB(callback, 0, 14);
01658       /* If bit 14 is set, then the company colours are applied to the
01659        * map else it's returned as-is. */
01660       if (!HasBit(callback, 14)) {
01661         /* Update cache */
01662         if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
01663         return map;
01664       }
01665     }
01666   }
01667 
01668   bool twocc = HasBit(e->info.misc_flags, EF_USES_2CC);
01669 
01670   if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
01671 
01672   /* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
01673   if (!Company::IsValidID(company)) return map;
01674 
01675   const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries);
01676 
01677   map += livery->colour1;
01678   if (twocc) map += livery->colour2 * 16;
01679 
01680   /* Update cache */
01681   if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
01682   return map;
01683 }
01684 
01691 PaletteID GetEnginePalette(EngineID engine_type, CompanyID company)
01692 {
01693   return GetEngineColourMap(engine_type, company, INVALID_ENGINE, NULL);
01694 }
01695 
01701 PaletteID GetVehiclePalette(const Vehicle *v)
01702 {
01703   if (v->IsGroundVehicle()) {
01704     return GetEngineColourMap(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v);
01705   }
01706 
01707   return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
01708 }
01709 
01718 uint GetVehicleCapacity(const Vehicle *v, uint16 *mail_capacity)
01719 {
01720   if (mail_capacity != NULL) *mail_capacity = 0;
01721   const Engine *e = Engine::Get(v->engine_type);
01722 
01723   if (!e->CanCarryCargo()) return 0;
01724 
01725   if (mail_capacity != NULL && e->type == VEH_AIRCRAFT && IsCargoInClass(v->cargo_type, CC_PASSENGERS)) {
01726     *mail_capacity = GetVehicleProperty(v, PROP_AIRCRAFT_MAIL_CAPACITY, e->u.air.mail_capacity);
01727   }
01728   CargoID default_cargo = e->GetDefaultCargoType();
01729 
01730   /* Check the refit capacity callback if we are not in the default configuration.
01731    * Note: This might change to become more consistent/flexible/sane, esp. when default cargo is first refittable. */
01732   if (HasBit(e->info.callback_mask, CBM_VEHICLE_REFIT_CAPACITY) &&
01733       (default_cargo != v->cargo_type || v->cargo_subtype != 0)) {
01734     uint16 callback = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, v->engine_type, v);
01735     if (callback != CALLBACK_FAILED) return callback;
01736   }
01737 
01738   /* Get capacity according to property resp. CB */
01739   uint capacity;
01740   switch (e->type) {
01741     case VEH_TRAIN:    capacity = GetVehicleProperty(v, PROP_TRAIN_CARGO_CAPACITY,        e->u.rail.capacity); break;
01742     case VEH_ROAD:     capacity = GetVehicleProperty(v, PROP_ROADVEH_CARGO_CAPACITY,      e->u.road.capacity); break;
01743     case VEH_SHIP:     capacity = GetVehicleProperty(v, PROP_SHIP_CARGO_CAPACITY,         e->u.ship.capacity); break;
01744     case VEH_AIRCRAFT: capacity = GetVehicleProperty(v, PROP_AIRCRAFT_PASSENGER_CAPACITY, e->u.air.passenger_capacity); break;
01745     default: NOT_REACHED();
01746   }
01747 
01748   /* Apply multipliers depending on cargo- and vehicletype.
01749    * Note: This might change to become more consistent/flexible. */
01750   if (e->type != VEH_SHIP) {
01751     if (e->type == VEH_AIRCRAFT) {
01752       if (!IsCargoInClass(v->cargo_type, CC_PASSENGERS)) {
01753         capacity += GetVehicleProperty(v, PROP_AIRCRAFT_MAIL_CAPACITY, e->u.air.mail_capacity);
01754       }
01755       if (v->cargo_type == CT_MAIL) return capacity;
01756     } else {
01757       switch (default_cargo) {
01758         case CT_PASSENGERS: break;
01759         case CT_MAIL:
01760         case CT_GOODS: capacity *= 2; break;
01761         default:       capacity *= 4; break;
01762       }
01763     }
01764     switch (v->cargo_type) {
01765       case CT_PASSENGERS: break;
01766       case CT_MAIL:
01767       case CT_GOODS: capacity /= 2; break;
01768       default:       capacity /= 4; break;
01769     }
01770   }
01771 
01772   return capacity;
01773 }
01774 
01778 void Vehicle::DeleteUnreachedAutoOrders()
01779 {
01780   const Order *order = this->GetOrder(this->cur_order_index);
01781   while (order != NULL && order->IsType(OT_AUTOMATIC)) {
01782     /* Delete order effectively deletes order, so get the next before deleting it. */
01783     order = order->next;
01784     DeleteOrder(this, this->cur_order_index);
01785   }
01786 }
01787 
01788 void Vehicle::BeginLoading()
01789 {
01790   assert(IsTileType(tile, MP_STATION) || type == VEH_SHIP);
01791 
01792   if (this->current_order.IsType(OT_GOTO_STATION) &&
01793       this->current_order.GetDestination() == this->last_station_visited) {
01794     this->DeleteUnreachedAutoOrders();
01795 
01796     /* Now cur_order_index points to the destination station, and we can start loading */
01797     this->current_order.MakeLoading(true);
01798     UpdateVehicleTimetable(this, true);
01799 
01800     /* Furthermore add the Non Stop flag to mark that this station
01801      * is the actual destination of the vehicle, which is (for example)
01802      * necessary to be known for HandleTrainLoading to determine
01803      * whether the train is lost or not; not marking a train lost
01804      * that arrives at random stations is bad. */
01805     this->current_order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
01806 
01807   } else {
01808     /* We weren't scheduled to stop here. Insert an automatic order
01809      * to show that we are stopping here, but only do that if the order
01810      * list isn't empty. */
01811     Order *in_list = this->GetOrder(this->cur_order_index);
01812     if (in_list != NULL && this->orders.list->GetNumOrders() < MAX_VEH_ORDER_ID &&
01813         (!in_list->IsType(OT_AUTOMATIC) ||
01814         in_list->GetDestination() != this->last_station_visited)) {
01815       Order *auto_order = new Order();
01816       auto_order->MakeAutomatic(this->last_station_visited);
01817       InsertOrder(this, auto_order, this->cur_order_index);
01818       if (this->cur_order_index > 0) --this->cur_order_index;
01819     }
01820     this->current_order.MakeLoading(false);
01821   }
01822 
01823   Station::Get(this->last_station_visited)->loading_vehicles.push_back(this);
01824 
01825   PrepareUnload(this);
01826 
01827   SetWindowDirty(GetWindowClassForVehicleType(this->type), this->owner);
01828   SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
01829   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
01830   SetWindowDirty(WC_STATION_VIEW, this->last_station_visited);
01831 
01832   Station::Get(this->last_station_visited)->MarkTilesDirty(true);
01833   this->cur_speed = 0;
01834   this->MarkDirty();
01835 }
01836 
01837 void Vehicle::LeaveStation()
01838 {
01839   assert(current_order.IsType(OT_LOADING));
01840 
01841   delete this->cargo_payment;
01842 
01843   /* Only update the timetable if the vehicle was supposed to stop here. */
01844   if (current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE) UpdateVehicleTimetable(this, false);
01845 
01846   current_order.MakeLeaveStation();
01847   Station *st = Station::Get(this->last_station_visited);
01848   st->loading_vehicles.remove(this);
01849 
01850   HideFillingPercent(&this->fill_percent_te_id);
01851 
01852   if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) {
01853     /* Trigger station animation (trains only) */
01854     if (IsTileType(this->tile, MP_STATION)) TriggerStationAnimation(st, this->tile, SAT_TRAIN_DEPARTS);
01855 
01856     SetBit(Train::From(this)->flags, VRF_LEAVING_STATION);
01857   }
01858 }
01859 
01860 
01866 void Vehicle::HandleLoading(bool mode)
01867 {
01868   switch (this->current_order.GetType()) {
01869     case OT_LOADING: {
01870       uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0);
01871 
01872       /* Not the first call for this tick, or still loading */
01873       if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) ||
01874           (_settings_game.order.timetabling && this->current_order_time < wait_time)) return;
01875 
01876       this->PlayLeaveStationSound();
01877 
01878       this->LeaveStation();
01879 
01880       break;
01881     }
01882 
01883     case OT_DUMMY: break;
01884 
01885     default: return;
01886   }
01887 
01888   this->IncrementOrderIndex();
01889 }
01890 
01897 CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command)
01898 {
01899   CommandCost ret = CheckOwnership(this->owner);
01900   if (ret.Failed()) return ret;
01901 
01902   if (this->vehstatus & VS_CRASHED) return CMD_ERROR;
01903   if (this->IsStoppedInDepot()) return CMD_ERROR;
01904 
01905   if (this->current_order.IsType(OT_GOTO_DEPOT)) {
01906     bool halt_in_depot = (this->current_order.GetDepotActionType() & ODATFB_HALT) != 0;
01907     if (!!(command & DEPOT_SERVICE) == halt_in_depot) {
01908       /* We called with a different DEPOT_SERVICE setting.
01909        * Now we change the setting to apply the new one and let the vehicle head for the same depot.
01910        * Note: the if is (true for requesting service == true for ordered to stop in depot)          */
01911       if (flags & DC_EXEC) {
01912         this->current_order.SetDepotOrderType(ODTF_MANUAL);
01913         this->current_order.SetDepotActionType(halt_in_depot ? ODATF_SERVICE_ONLY : ODATFB_HALT);
01914         SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
01915       }
01916       return CommandCost();
01917     }
01918 
01919     if (command & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
01920     if (flags & DC_EXEC) {
01921       /* If the orders to 'goto depot' are in the orders list (forced servicing),
01922        * then skip to the next order; effectively cancelling this forced service */
01923       if (this->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) this->IncrementOrderIndex();
01924 
01925       this->current_order.MakeDummy();
01926       SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
01927     }
01928     return CommandCost();
01929   }
01930 
01931   TileIndex location;
01932   DestinationID destination;
01933   bool reverse;
01934   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};
01935   if (!this->FindClosestDepot(&location, &destination, &reverse)) return_cmd_error(no_depot[this->type]);
01936 
01937   if (flags & DC_EXEC) {
01938     if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
01939 
01940     this->dest_tile = location;
01941     this->current_order.MakeGoToDepot(destination, ODTF_MANUAL);
01942     if (!(command & DEPOT_SERVICE)) this->current_order.SetDepotActionType(ODATFB_HALT);
01943     SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
01944 
01945     /* If there is no depot in front, reverse automatically (trains only) */
01946     if (this->type == VEH_TRAIN && reverse) DoCommand(this->tile, this->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
01947 
01948     if (this->type == VEH_AIRCRAFT) {
01949       Aircraft *a = Aircraft::From(this);
01950       if (a->state == FLYING && a->targetairport != destination) {
01951         /* The aircraft is now heading for a different hangar than the next in the orders */
01952         extern void AircraftNextAirportPos_and_Order(Aircraft *a);
01953         AircraftNextAirportPos_and_Order(a);
01954       }
01955     }
01956   }
01957 
01958   return CommandCost();
01959 
01960 }
01961 
01966 void Vehicle::UpdateVisualEffect(bool allow_power_change)
01967 {
01968   bool powered_before = HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
01969   const Engine *e = Engine::Get(this->engine_type);
01970 
01971   /* Evaluate properties */
01972   byte visual_effect;
01973   switch (e->type) {
01974     case VEH_TRAIN: visual_effect = e->u.rail.visual_effect; break;
01975     case VEH_ROAD:  visual_effect = e->u.road.visual_effect; break;
01976     case VEH_SHIP:  visual_effect = e->u.ship.visual_effect; break;
01977     default:        visual_effect = 1 << VE_DISABLE_EFFECT;  break;
01978   }
01979 
01980   /* Check powered wagon / visual effect callback */
01981   if (HasBit(e->info.callback_mask, CBM_VEHICLE_VISUAL_EFFECT)) {
01982     uint16 callback = GetVehicleCallback(CBID_VEHICLE_VISUAL_EFFECT, 0, 0, this->engine_type, this);
01983 
01984     if (callback != CALLBACK_FAILED) {
01985       callback = GB(callback, 0, 8);
01986       /* Avoid accidentally setting 'visual_effect' to the default value
01987        * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
01988       if (callback == VE_DEFAULT) {
01989         assert(HasBit(callback, VE_DISABLE_EFFECT));
01990         SB(callback, VE_TYPE_START, VE_TYPE_COUNT, 0);
01991       }
01992       visual_effect = callback;
01993     }
01994   }
01995 
01996   /* Apply default values */
01997   if (visual_effect == VE_DEFAULT ||
01998       (!HasBit(visual_effect, VE_DISABLE_EFFECT) && GB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT) == VE_TYPE_DEFAULT)) {
01999     /* Only train engines have default effects.
02000      * Note: This is independent of whether the engine is a front engine or articulated part or whatever. */
02001     if (e->type != VEH_TRAIN || e->u.rail.railveh_type == RAILVEH_WAGON || !IsInsideMM(e->u.rail.engclass, EC_STEAM, EC_MONORAIL)) {
02002       if (visual_effect == VE_DEFAULT) {
02003         visual_effect = 1 << VE_DISABLE_EFFECT;
02004       } else {
02005         SetBit(visual_effect, VE_DISABLE_EFFECT);
02006       }
02007     } else {
02008       if (visual_effect == VE_DEFAULT) {
02009         /* Also set the offset */
02010         visual_effect = (VE_OFFSET_CENTRE - (e->u.rail.engclass == EC_STEAM ? 4 : 0)) << VE_OFFSET_START;
02011       }
02012       SB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT, e->u.rail.engclass - EC_STEAM + VE_TYPE_STEAM);
02013     }
02014   }
02015 
02016   this->vcache.cached_vis_effect = visual_effect;
02017 
02018   if (!allow_power_change && powered_before != HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
02019     ToggleBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
02020     ShowNewGrfVehicleError(this->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_POWERED_WAGON, GBUG_VEH_POWERED_WAGON, false);
02021   }
02022 }
02023 
02024 static const int8 _vehicle_smoke_pos[8] = {
02025   1, 1, 1, 0, -1, -1, -1, 0
02026 };
02027 
02032 void Vehicle::ShowVisualEffect() const
02033 {
02034   assert(this->IsPrimaryVehicle());
02035   bool sound = false;
02036 
02037   /* Do not show any smoke when:
02038    * - vehicle smoke is disabled by the player
02039    * - the vehicle is slowing down or stopped (by the player)
02040    * - the vehicle is moving very slowly
02041    */
02042   if (_settings_game.vehicle.smoke_amount == 0 ||
02043       this->vehstatus & (VS_TRAIN_SLOWING | VS_STOPPED) ||
02044       this->cur_speed < 2) {
02045     return;
02046   }
02047   if (this->type == VEH_TRAIN) {
02048     const Train *t = Train::From(this);
02049     /* For trains, do not show any smoke when:
02050      * - the train is reversing
02051      * - is entering a station with an order to stop there and its speed is equal to maximum station entering speed
02052      */
02053     if (HasBit(t->flags, VRF_REVERSING) ||
02054         (IsRailStationTile(t->tile) && t->IsFrontEngine() && t->current_order.ShouldStopAtStation(t, GetStationIndex(t->tile)) &&
02055         t->cur_speed >= t->Train::GetCurrentMaxSpeed())) {
02056       return;
02057     }
02058   }
02059 
02060   const Vehicle *v = this;
02061 
02062   do {
02063     int effect_offset = GB(v->vcache.cached_vis_effect, VE_OFFSET_START, VE_OFFSET_COUNT) - VE_OFFSET_CENTRE;
02064     byte effect_type = GB(v->vcache.cached_vis_effect, VE_TYPE_START, VE_TYPE_COUNT);
02065     bool disable_effect = HasBit(v->vcache.cached_vis_effect, VE_DISABLE_EFFECT);
02066 
02067     /* Show no smoke when:
02068      * - Smoke has been disabled for this vehicle
02069      * - The vehicle is not visible
02070      * - The vehicle is on a depot tile
02071      * - The vehicle is on a tunnel tile
02072      * - The vehicle is a train engine that is currently unpowered */
02073     if (disable_effect ||
02074         v->vehstatus & VS_HIDDEN ||
02075         IsDepotTile(v->tile) ||
02076         IsTunnelTile(v->tile) ||
02077         (v->type == VEH_TRAIN &&
02078         !HasPowerOnRail(Train::From(v)->railtype, GetTileRailType(v->tile)))) {
02079       continue;
02080     }
02081 
02082     int x = _vehicle_smoke_pos[v->direction] * effect_offset;
02083     int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
02084 
02085     if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) {
02086       x = -x;
02087       y = -y;
02088     }
02089 
02090     switch (effect_type) {
02091       case VE_TYPE_STEAM:
02092         /* Steam smoke - amount is gradually falling until vehicle reaches its maximum speed, after that it's normal.
02093          * Details: while vehicle's current speed is gradually increasing, steam plumes' density decreases by one third each
02094          * third of its maximum speed spectrum. Steam emission finally normalises at very close to vehicle's maximum speed.
02095          * REGULATION:
02096          * - instead of 1, 4 / 2^smoke_amount (max. 2) is used to provide sufficient regulation to steam puffs' amount. */
02097         if (GB(v->tick_counter, 0, ((4 >> _settings_game.vehicle.smoke_amount) + ((this->cur_speed * 3) / this->vcache.cached_max_speed))) == 0) {
02098           CreateEffectVehicleRel(v, x, y, 10, EV_STEAM_SMOKE);
02099           sound = true;
02100         }
02101         break;
02102 
02103       case VE_TYPE_DIESEL: {
02104         /* Diesel smoke - thicker when vehicle is starting, gradually subsiding till it reaches its maximum speed
02105          * when smoke emission stops.
02106          * Details: Vehicle's (max.) speed spectrum is divided into 32 parts. When max. speed is reached, chance for smoke
02107          * emission erodes by 32 (1/4). For trains, power and weight come in handy too to either increase smoke emission in
02108          * 6 steps (1000HP each) if the power is low or decrease smoke emission in 6 steps (512 tonnes each) if the train
02109          * isn't overweight. Power and weight contributions are expressed in a way that neither extreme power, nor
02110          * extreme weight can ruin the balance (e.g. FreightWagonMultiplier) in the formula. When the vehicle reaches
02111          * maximum speed no diesel_smoke is emitted.
02112          * REGULATION:
02113          * - up to which speed a diesel vehicle is emitting smoke (with reduced/small setting only until 1/2 of max_speed),
02114          * - in Chance16 - the last value is 512 / 2^smoke_amount (max. smoke when 128 = smoke_amount of 2). */
02115         int power_weight_effect = 0;
02116         if (v->type == VEH_TRAIN) {
02117           power_weight_effect = (32 >> (Train::From(this)->gcache.cached_power >> 10)) - (32 >> (Train::From(this)->gcache.cached_weight >> 9));
02118         }
02119         if (this->cur_speed < (this->vcache.cached_max_speed >> (2 >> _settings_game.vehicle.smoke_amount)) &&
02120             Chance16((64 - ((this->cur_speed << 5) / this->vcache.cached_max_speed) + power_weight_effect), (512 >> _settings_game.vehicle.smoke_amount))) {
02121           CreateEffectVehicleRel(v, x, y, 10, EV_DIESEL_SMOKE);
02122           sound = true;
02123         }
02124         break;
02125       }
02126 
02127       case VE_TYPE_ELECTRIC:
02128         /* Electric train's spark - more often occurs when train is departing (more load)
02129          * Details: Electric locomotives are usually at least twice as powerful as their diesel counterparts, so spark
02130          * emissions are kept simple. Only when starting, creating huge force are sparks more likely to happen, but when
02131          * reaching its max. speed, quarter by quarter of it, chance decreases untill the usuall 2,22% at train's top speed.
02132          * REGULATION:
02133          * - in Chance16 the last value is 360 / 2^smoke_amount (max. sparks when 90 = smoke_amount of 2). */
02134         if (GB(v->tick_counter, 0, 2) == 0 &&
02135             Chance16((6 - ((this->cur_speed << 2) / this->vcache.cached_max_speed)), (360 >> _settings_game.vehicle.smoke_amount))) {
02136           CreateEffectVehicleRel(v, x, y, 10, EV_ELECTRIC_SPARK);
02137           sound = true;
02138         }
02139         break;
02140 
02141       default:
02142         break;
02143     }
02144   } while ((v = v->Next()) != NULL);
02145 
02146   if (sound) PlayVehicleSound(this, VSE_VISUAL_EFFECT);
02147 }
02148 
02153 void Vehicle::SetNext(Vehicle *next)
02154 {
02155   assert(this != next);
02156 
02157   if (this->next != NULL) {
02158     /* We had an old next vehicle. Update the first and previous pointers */
02159     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
02160       v->first = this->next;
02161     }
02162     this->next->previous = NULL;
02163   }
02164 
02165   this->next = next;
02166 
02167   if (this->next != NULL) {
02168     /* A new next vehicle. Update the first and previous pointers */
02169     if (this->next->previous != NULL) this->next->previous->next = NULL;
02170     this->next->previous = this;
02171     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
02172       v->first = this->first;
02173     }
02174   }
02175 }
02176 
02182 void Vehicle::AddToShared(Vehicle *shared_chain)
02183 {
02184   assert(this->previous_shared == NULL && this->next_shared == NULL);
02185 
02186   if (!shared_chain->orders.list) {
02187     assert(shared_chain->previous_shared == NULL);
02188     assert(shared_chain->next_shared == NULL);
02189     this->orders.list = shared_chain->orders.list = new OrderList(NULL, shared_chain);
02190   }
02191 
02192   this->next_shared     = shared_chain->next_shared;
02193   this->previous_shared = shared_chain;
02194 
02195   shared_chain->next_shared = this;
02196 
02197   if (this->next_shared != NULL) this->next_shared->previous_shared = this;
02198 
02199   shared_chain->orders.list->AddVehicle(this);
02200 }
02201 
02205 void Vehicle::RemoveFromShared()
02206 {
02207   /* Remember if we were first and the old window number before RemoveVehicle()
02208    * as this changes first if needed. */
02209   bool were_first = (this->FirstShared() == this);
02210   VehicleListIdentifier vli(VL_SHARED_ORDERS, this->type, this->owner, this->FirstShared()->index);
02211 
02212   this->orders.list->RemoveVehicle(this);
02213 
02214   if (!were_first) {
02215     /* We are not the first shared one, so only relink our previous one. */
02216     this->previous_shared->next_shared = this->NextShared();
02217   }
02218 
02219   if (this->next_shared != NULL) this->next_shared->previous_shared = this->previous_shared;
02220 
02221 
02222   if (this->orders.list->GetNumVehicles() == 1) {
02223     /* When there is only one vehicle, remove the shared order list window. */
02224     DeleteWindowById(GetWindowClassForVehicleType(this->type), vli.Pack());
02225     InvalidateVehicleOrder(this->FirstShared(), 0);
02226   } else if (were_first) {
02227     /* If we were the first one, update to the new first one.
02228      * Note: FirstShared() is already the new first */
02229     InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.Pack(), this->FirstShared()->index | (1U << 31));
02230   }
02231 
02232   this->next_shared     = NULL;
02233   this->previous_shared = NULL;
02234 }
02235 
02241 Order *Vehicle::GetNextManualOrder(int index) const
02242 {
02243   Order *order = this->GetOrder(index);
02244   while(order != NULL && order->IsType(OT_AUTOMATIC)) {
02245     order = order->next;
02246   }
02247   return order;
02248 }
02249 
02250 void VehiclesYearlyLoop()
02251 {
02252   Vehicle *v;
02253   FOR_ALL_VEHICLES(v) {
02254     if (v->IsPrimaryVehicle()) {
02255       /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
02256       Money profit = v->GetDisplayProfitThisYear();
02257       if (v->age >= 730 && profit < 0) {
02258         if (_settings_client.gui.vehicle_income_warn && v->owner == _local_company) {
02259           SetDParam(0, v->index);
02260           SetDParam(1, profit);
02261           AddVehicleNewsItem(
02262             STR_NEWS_VEHICLE_IS_UNPROFITABLE,
02263             NS_ADVICE,
02264             v->index
02265           );
02266         }
02267         AI::NewEvent(v->owner, new AIEventVehicleUnprofitable(v->index));
02268       }
02269 
02270       v->profit_last_year = v->profit_this_year;
02271       v->profit_this_year = 0;
02272       SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
02273     }
02274   }
02275 }
02276 
02277 
02287 bool CanVehicleUseStation(EngineID engine_type, const Station *st)
02288 {
02289   const Engine *e = Engine::GetIfValid(engine_type);
02290   assert(e != NULL);
02291 
02292   switch (e->type) {
02293     case VEH_TRAIN:
02294       return (st->facilities & FACIL_TRAIN) != 0;
02295 
02296     case VEH_ROAD:
02297       /* For road vehicles we need the vehicle to know whether it can actually
02298        * use the station, but if it doesn't have facilities for RVs it is
02299        * certainly not possible that the station can be used. */
02300       return (st->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP)) != 0;
02301 
02302     case VEH_SHIP:
02303       return (st->facilities & FACIL_DOCK) != 0;
02304 
02305     case VEH_AIRCRAFT:
02306       return (st->facilities & FACIL_AIRPORT) != 0 &&
02307           (st->airport.GetFTA()->flags & (e->u.air.subtype & AIR_CTOL ? AirportFTAClass::AIRPLANES : AirportFTAClass::HELICOPTERS)) != 0;
02308 
02309     default:
02310       return false;
02311   }
02312 }
02313 
02320 bool CanVehicleUseStation(const Vehicle *v, const Station *st)
02321 {
02322   if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != NULL;
02323 
02324   return CanVehicleUseStation(v->engine_type, st);
02325 }
02326 
02332 GroundVehicleCache *Vehicle::GetGroundVehicleCache()
02333 {
02334   assert(this->IsGroundVehicle());
02335   if (this->type == VEH_TRAIN) {
02336     return &Train::From(this)->gcache;
02337   } else {
02338     return &RoadVehicle::From(this)->gcache;
02339   }
02340 }
02341 
02347 const GroundVehicleCache *Vehicle::GetGroundVehicleCache() const
02348 {
02349   assert(this->IsGroundVehicle());
02350   if (this->type == VEH_TRAIN) {
02351     return &Train::From(this)->gcache;
02352   } else {
02353     return &RoadVehicle::From(this)->gcache;
02354   }
02355 }
02356 
02365 void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8 num_vehicles)
02366 {
02367   if (v->type == VEH_TRAIN) {
02368     Train *u = Train::From(v);
02369     /* If the first vehicle in the selection is part of an articulated vehicle, add the previous parts of the vehicle. */
02370     if (u->IsArticulatedPart()) {
02371       u = u->GetFirstEnginePart();
02372       while (u->index != v->index) {
02373         set.Include(u->index);
02374         u = u->GetNextArticulatedPart();
02375       }
02376     }
02377 
02378     for (;u != NULL && num_vehicles > 0; num_vehicles--, u = u->Next()) {
02379       /* Include current vehicle in the selection. */
02380       set.Include(u->index);
02381 
02382       /* If the vehicle is multiheaded, add the other part too. */
02383       if (u->IsMultiheaded()) set.Include(u->other_multiheaded_part->index);
02384     }
02385 
02386     /* If the last vehicle is part of an articulated vehicle, add the following parts of the vehicle. */
02387     while (u != NULL && u->IsArticulatedPart()) {
02388       set.Include(u->index);
02389       u = u->Next();
02390     }
02391   }
02392 }

Generated on Sun Jan 23 01:49:12 2011 for OpenTTD by  doxygen 1.6.1