vehicle.cpp

Go to the documentation of this file.
00001 /* $Id: vehicle.cpp 21860 2011-01-19 18:44:13Z terkhen $ */
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 #include "ground_vehicle.hpp"
00056 
00057 #include "table/strings.h"
00058 
00059 #define GEN_HASH(x, y) ((GB((y), 6, 6) << 6) + GB((x), 7, 6))
00060 
00061 VehicleID _new_vehicle_id;
00062 uint16 _returned_refit_capacity;      
00063 uint16 _returned_mail_refit_capacity; 
00064 byte _age_cargo_skip_counter;         
00065 
00066 
00067 /* Initialize the vehicle-pool */
00068 VehiclePool _vehicle_pool("Vehicle");
00069 INSTANTIATE_POOL_METHODS(Vehicle)
00070 
00071 
00076 bool Vehicle::NeedsAutorenewing(const Company *c) const
00077 {
00078   /* We can always generate the Company pointer when we have the vehicle.
00079    * However this takes time and since the Company pointer is often present
00080    * when this function is called then it's faster to pass the pointer as an
00081    * argument rather than finding it again. */
00082   assert(c == Company::Get(this->owner));
00083 
00084   if (!c->settings.engine_renew) return false;
00085   if (this->age - this->max_age < (c->settings.engine_renew_months * 30)) return false;
00086   if (this->age == 0) return false; // rail cars don't age and lacks a max age
00087 
00088   return true;
00089 }
00090 
00091 void VehicleServiceInDepot(Vehicle *v)
00092 {
00093   v->date_of_last_service = _date;
00094   v->breakdowns_since_last_service = 0;
00095   v->reliability = Engine::Get(v->engine_type)->reliability;
00096   SetWindowDirty(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
00097 }
00098 
00105 bool Vehicle::NeedsServicing() const
00106 {
00107   /* Stopped or crashed vehicles will not move, as such making unmovable
00108    * vehicles to go for service is lame. */
00109   if (this->vehstatus & (VS_STOPPED | VS_CRASHED)) return false;
00110 
00111   /* Are we ready for the next service cycle? */
00112   const Company *c = Company::Get(this->owner);
00113   if (c->settings.vehicle.servint_ispercent ?
00114       (this->reliability >= Engine::Get(this->engine_type)->reliability * (100 - this->service_interval) / 100) :
00115       (this->date_of_last_service + this->service_interval >= _date)) {
00116     return false;
00117   }
00118 
00119   /* If we're servicing anyway, because we have not disabled servicing when
00120    * there are no breakdowns or we are playing with breakdowns, bail out. */
00121   if (!_settings_game.order.no_servicing_if_no_breakdowns ||
00122       _settings_game.difficulty.vehicle_breakdowns != 0) {
00123     return true;
00124   }
00125 
00126   /* Test whether there is some pending autoreplace.
00127    * Note: We do this after the service-interval test.
00128    * There are a lot more reasons for autoreplace to fail than we can test here reasonably. */
00129   bool pending_replace = false;
00130   Money needed_money = c->settings.engine_renew_money;
00131   if (needed_money > c->money) return false;
00132 
00133   for (const Vehicle *v = this; v != NULL; v = (v->type == VEH_TRAIN) ? Train::From(v)->GetNextUnit() : NULL) {
00134     EngineID new_engine = EngineReplacementForCompany(c, v->engine_type, v->group_id);
00135 
00136     /* Check engine availability */
00137     if (new_engine == INVALID_ENGINE || !HasBit(Engine::Get(new_engine)->company_avail, v->owner)) continue;
00138 
00139     /* Check refittability */
00140     uint32 available_cargo_types, union_mask;
00141     GetArticulatedRefitMasks(new_engine, true, &union_mask, &available_cargo_types);
00142     /* Is there anything to refit? */
00143     if (union_mask != 0) {
00144       CargoID cargo_type;
00145       /* We cannot refit to mixed cargoes in an automated way */
00146       if (IsArticulatedVehicleCarryingDifferentCargos(v, &cargo_type)) continue;
00147 
00148       /* Did the old vehicle carry anything? */
00149       if (cargo_type != CT_INVALID) {
00150         /* We can't refit the vehicle to carry the cargo we want */
00151         if (!HasBit(available_cargo_types, cargo_type)) continue;
00152       }
00153     }
00154 
00155     /* Check money.
00156      * We want 2*(the price of the new vehicle) without looking at the value of the vehicle we are going to sell. */
00157     pending_replace = true;
00158     needed_money += 2 * Engine::Get(new_engine)->GetCost();
00159     if (needed_money > c->money) return false;
00160   }
00161 
00162   return pending_replace;
00163 }
00164 
00170 bool Vehicle::NeedsAutomaticServicing() const
00171 {
00172   if (_settings_game.order.gotodepot && this->HasDepotOrder()) return false;
00173   if (this->current_order.IsType(OT_LOADING)) return false;
00174   if (this->current_order.IsType(OT_GOTO_DEPOT) && this->current_order.GetDepotOrderType() != ODTFB_SERVICE) return false;
00175   return NeedsServicing();
00176 }
00177 
00178 uint Vehicle::Crash(bool flooded)
00179 {
00180   assert((this->vehstatus & VS_CRASHED) == 0);
00181   assert(this->Previous() == NULL); // IsPrimaryVehicle fails for free-wagon-chains
00182 
00183   uint pass = 0;
00184   /* Stop the vehicle. */
00185   if (this->IsPrimaryVehicle()) this->vehstatus |= VS_STOPPED;
00186   /* crash all wagons, and count passengers */
00187   for (Vehicle *v = this; v != NULL; v = v->Next()) {
00188     if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) pass += v->cargo.Count();
00189     v->vehstatus |= VS_CRASHED;
00190     MarkSingleVehicleDirty(v);
00191   }
00192 
00193   /* Dirty some windows */
00194   InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
00195   SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
00196   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
00197   SetWindowDirty(WC_VEHICLE_DEPOT, this->tile);
00198 
00199   return pass;
00200 }
00201 
00202 
00211 void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical)
00212 {
00213   const Engine *e = Engine::Get(engine);
00214   uint32 grfid = e->grf_prop.grffile->grfid;
00215   GRFConfig *grfconfig = GetGRFConfig(grfid);
00216 
00217   if (!HasBit(grfconfig->grf_bugs, bug_type)) {
00218     SetBit(grfconfig->grf_bugs, bug_type);
00219     SetDParamStr(0, grfconfig->GetName());
00220     SetDParam(1, engine);
00221     ShowErrorMessage(part1, part2, WL_CRITICAL);
00222     if (!_networking) DoCommand(0, critical ? PM_PAUSED_ERROR : PM_PAUSED_NORMAL, 1, DC_EXEC, CMD_PAUSE);
00223   }
00224 
00225   /* debug output */
00226   char buffer[512];
00227 
00228   SetDParamStr(0, grfconfig->GetName());
00229   GetString(buffer, part1, lastof(buffer));
00230   DEBUG(grf, 0, "%s", buffer + 3);
00231 
00232   SetDParam(1, engine);
00233   GetString(buffer, part2, lastof(buffer));
00234   DEBUG(grf, 0, "%s", buffer + 3);
00235 }
00236 
00241 Vehicle::Vehicle(VehicleType type)
00242 {
00243   this->type               = type;
00244   this->coord.left         = INVALID_COORD;
00245   this->group_id           = DEFAULT_GROUP;
00246   this->fill_percent_te_id = INVALID_TE_ID;
00247   this->first              = this;
00248   this->colourmap          = PAL_NONE;
00249 }
00250 
00255 byte VehicleRandomBits()
00256 {
00257   return GB(Random(), 0, 8);
00258 }
00259 
00260 /* Size of the hash, 6 = 64 x 64, 7 = 128 x 128. Larger sizes will (in theory) reduce hash
00261  * lookup times at the expense of memory usage. */
00262 const int HASH_BITS = 7;
00263 const int HASH_SIZE = 1 << HASH_BITS;
00264 const int HASH_MASK = HASH_SIZE - 1;
00265 const int TOTAL_HASH_SIZE = 1 << (HASH_BITS * 2);
00266 const int TOTAL_HASH_MASK = TOTAL_HASH_SIZE - 1;
00267 
00268 /* Resolution of the hash, 0 = 1*1 tile, 1 = 2*2 tiles, 2 = 4*4 tiles, etc.
00269  * Profiling results show that 0 is fastest. */
00270 const int HASH_RES = 0;
00271 
00272 static Vehicle *_new_vehicle_position_hash[TOTAL_HASH_SIZE];
00273 
00274 static Vehicle *VehicleFromHash(int xl, int yl, int xu, int yu, void *data, VehicleFromPosProc *proc, bool find_first)
00275 {
00276   for (int y = yl; ; y = (y + (1 << HASH_BITS)) & (HASH_MASK << HASH_BITS)) {
00277     for (int x = xl; ; x = (x + 1) & HASH_MASK) {
00278       Vehicle *v = _new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
00279       for (; v != NULL; v = v->next_new_hash) {
00280         Vehicle *a = proc(v, data);
00281         if (find_first && a != NULL) return a;
00282       }
00283       if (x == xu) break;
00284     }
00285     if (y == yu) break;
00286   }
00287 
00288   return NULL;
00289 }
00290 
00291 
00303 static Vehicle *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc, bool find_first)
00304 {
00305   const int COLL_DIST = 6;
00306 
00307   /* Hash area to scan is from xl,yl to xu,yu */
00308   int xl = GB((x - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
00309   int xu = GB((x + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
00310   int yl = GB((y - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
00311   int yu = GB((y + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
00312 
00313   return VehicleFromHash(xl, yl, xu, yu, data, proc, find_first);
00314 }
00315 
00330 void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
00331 {
00332   VehicleFromPosXY(x, y, data, proc, false);
00333 }
00334 
00346 bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
00347 {
00348   return VehicleFromPosXY(x, y, data, proc, true) != NULL;
00349 }
00350 
00361 static Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc, bool find_first)
00362 {
00363   int x = GB(TileX(tile), HASH_RES, HASH_BITS);
00364   int y = GB(TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS;
00365 
00366   Vehicle *v = _new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
00367   for (; v != NULL; v = v->next_new_hash) {
00368     if (v->tile != tile) continue;
00369 
00370     Vehicle *a = proc(v, data);
00371     if (find_first && a != NULL) return a;
00372   }
00373 
00374   return NULL;
00375 }
00376 
00390 void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
00391 {
00392   VehicleFromPos(tile, data, proc, false);
00393 }
00394 
00405 bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
00406 {
00407   return VehicleFromPos(tile, data, proc, true) != NULL;
00408 }
00409 
00416 static Vehicle *EnsureNoVehicleProcZ(Vehicle *v, void *data)
00417 {
00418   byte z = *(byte*)data;
00419 
00420   if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
00421   if (v->z_pos > z) return NULL;
00422 
00423   return v;
00424 }
00425 
00431 CommandCost EnsureNoVehicleOnGround(TileIndex tile)
00432 {
00433   byte z = GetTileMaxZ(tile);
00434 
00435   /* Value v is not safe in MP games, however, it is used to generate a local
00436    * error message only (which may be different for different machines).
00437    * Such a message does not affect MP synchronisation.
00438    */
00439   Vehicle *v = VehicleFromPos(tile, &z, &EnsureNoVehicleProcZ, true);
00440   if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
00441   return CommandCost();
00442 }
00443 
00445 static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
00446 {
00447   if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) return NULL;
00448   if (v == (const Vehicle *)data) return NULL;
00449 
00450   return v;
00451 }
00452 
00460 CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore)
00461 {
00462   /* Value v is not safe in MP games, however, it is used to generate a local
00463    * error message only (which may be different for different machines).
00464    * Such a message does not affect MP synchronisation.
00465    */
00466   Vehicle *v = VehicleFromPos(tile, (void *)ignore, &GetVehicleTunnelBridgeProc, true);
00467   if (v == NULL) v = VehicleFromPos(endtile, (void *)ignore, &GetVehicleTunnelBridgeProc, true);
00468 
00469   if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
00470   return CommandCost();
00471 }
00472 
00473 static Vehicle *EnsureNoTrainOnTrackProc(Vehicle *v, void *data)
00474 {
00475   TrackBits rail_bits = *(TrackBits *)data;
00476 
00477   if (v->type != VEH_TRAIN) return NULL;
00478 
00479   Train *t = Train::From(v);
00480   if ((t->track != rail_bits) && !TracksOverlap(t->track | rail_bits)) return NULL;
00481 
00482   return v;
00483 }
00484 
00493 CommandCost EnsureNoTrainOnTrackBits(TileIndex tile, TrackBits track_bits)
00494 {
00495   /* Value v is not safe in MP games, however, it is used to generate a local
00496    * error message only (which may be different for different machines).
00497    * Such a message does not affect MP synchronisation.
00498    */
00499   Vehicle *v = VehicleFromPos(tile, &track_bits, &EnsureNoTrainOnTrackProc, true);
00500   if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
00501   return CommandCost();
00502 }
00503 
00504 static void UpdateNewVehiclePosHash(Vehicle *v, bool remove)
00505 {
00506   Vehicle **old_hash = v->old_new_hash;
00507   Vehicle **new_hash;
00508 
00509   if (remove) {
00510     new_hash = NULL;
00511   } else {
00512     int x = GB(TileX(v->tile), HASH_RES, HASH_BITS);
00513     int y = GB(TileY(v->tile), HASH_RES, HASH_BITS) << HASH_BITS;
00514     new_hash = &_new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
00515   }
00516 
00517   if (old_hash == new_hash) return;
00518 
00519   /* Remove from the old position in the hash table */
00520   if (old_hash != NULL) {
00521     if (v->next_new_hash != NULL) v->next_new_hash->prev_new_hash = v->prev_new_hash;
00522     *v->prev_new_hash = v->next_new_hash;
00523   }
00524 
00525   /* Insert vehicle at beginning of the new position in the hash table */
00526   if (new_hash != NULL) {
00527     v->next_new_hash = *new_hash;
00528     if (v->next_new_hash != NULL) v->next_new_hash->prev_new_hash = &v->next_new_hash;
00529     v->prev_new_hash = new_hash;
00530     *new_hash = v;
00531   }
00532 
00533   /* Remember current hash position */
00534   v->old_new_hash = new_hash;
00535 }
00536 
00537 static Vehicle *_vehicle_position_hash[0x1000];
00538 
00539 static void UpdateVehiclePosHash(Vehicle *v, int x, int y)
00540 {
00541   UpdateNewVehiclePosHash(v, x == INVALID_COORD);
00542 
00543   Vehicle **old_hash, **new_hash;
00544   int old_x = v->coord.left;
00545   int old_y = v->coord.top;
00546 
00547   new_hash = (x == INVALID_COORD) ? NULL : &_vehicle_position_hash[GEN_HASH(x, y)];
00548   old_hash = (old_x == INVALID_COORD) ? NULL : &_vehicle_position_hash[GEN_HASH(old_x, old_y)];
00549 
00550   if (old_hash == new_hash) return;
00551 
00552   /* remove from hash table? */
00553   if (old_hash != NULL) {
00554     if (v->next_hash != NULL) v->next_hash->prev_hash = v->prev_hash;
00555     *v->prev_hash = v->next_hash;
00556   }
00557 
00558   /* insert into hash table? */
00559   if (new_hash != NULL) {
00560     v->next_hash = *new_hash;
00561     if (v->next_hash != NULL) v->next_hash->prev_hash = &v->next_hash;
00562     v->prev_hash = new_hash;
00563     *new_hash = v;
00564   }
00565 }
00566 
00567 void ResetVehiclePosHash()
00568 {
00569   Vehicle *v;
00570   FOR_ALL_VEHICLES(v) { v->old_new_hash = NULL; }
00571   memset(_vehicle_position_hash, 0, sizeof(_vehicle_position_hash));
00572   memset(_new_vehicle_position_hash, 0, sizeof(_new_vehicle_position_hash));
00573 }
00574 
00575 void ResetVehicleColourMap()
00576 {
00577   Vehicle *v;
00578   FOR_ALL_VEHICLES(v) { v->colourmap = PAL_NONE; }
00579 }
00580 
00585 typedef SmallMap<Vehicle *, bool, 4> AutoreplaceMap;
00586 static AutoreplaceMap _vehicles_to_autoreplace;
00587 
00588 void InitializeVehicles()
00589 {
00590   _vehicle_pool.CleanPool();
00591   _cargo_payment_pool.CleanPool();
00592 
00593   _age_cargo_skip_counter = 1;
00594 
00595   _vehicles_to_autoreplace.Reset();
00596   ResetVehiclePosHash();
00597 }
00598 
00599 uint CountVehiclesInChain(const Vehicle *v)
00600 {
00601   uint count = 0;
00602   do count++; while ((v = v->Next()) != NULL);
00603   return count;
00604 }
00605 
00611 void CountCompanyVehicles(CompanyID cid, uint counts[4])
00612 {
00613   for (uint i = 0; i < 4; i++) counts[i] = 0;
00614 
00615   const Vehicle *v;
00616   FOR_ALL_VEHICLES(v) {
00617     if (v->owner == cid && v->IsPrimaryVehicle()) counts[v->type]++;
00618   }
00619 }
00620 
00625 bool Vehicle::IsEngineCountable() const
00626 {
00627   switch (this->type) {
00628     case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft(); // don't count plane shadows and helicopter rotors
00629     case VEH_TRAIN:
00630       return !Train::From(this)->IsArticulatedPart() && // tenders and other articulated parts
00631           !Train::From(this)->IsRearDualheaded(); // rear parts of multiheaded engines
00632     case VEH_ROAD: return RoadVehicle::From(this)->IsFrontEngine();
00633     case VEH_SHIP: return true;
00634     default: return false; // Only count company buildable vehicles
00635   }
00636 }
00637 
00645 void Vehicle::HandlePathfindingResult(bool path_found)
00646 {
00647   if (path_found) {
00648     /* Route found, is the vehicle marked with "lost" flag? */
00649     if (!HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;
00650 
00651     /* Clear the flag as the PF's problem was solved. */
00652     ClrBit(this->vehicle_flags, VF_PATHFINDER_LOST);
00653     /* Delete the news item. */
00654     DeleteVehicleNews(this->index, STR_NEWS_VEHICLE_IS_LOST);
00655     return;
00656   }
00657 
00658   /* Were we already lost? */
00659   if (HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return;
00660 
00661   /* It is first time the problem occurred, set the "lost" flag. */
00662   SetBit(this->vehicle_flags, VF_PATHFINDER_LOST);
00663   /* Notify user about the event. */
00664   AI::NewEvent(this->owner, new AIEventVehicleLost(this->index));
00665   if (_settings_client.gui.lost_vehicle_warn && this->owner == _local_company) {
00666     SetDParam(0, this->index);
00667     AddVehicleNewsItem(STR_NEWS_VEHICLE_IS_LOST, NS_ADVICE, this->index);
00668   }
00669 }
00670 
00672 void Vehicle::PreDestructor()
00673 {
00674   if (CleaningPool()) return;
00675 
00676   if (Station::IsValidID(this->last_station_visited)) {
00677     Station::Get(this->last_station_visited)->loading_vehicles.remove(this);
00678 
00679     HideFillingPercent(&this->fill_percent_te_id);
00680 
00681     delete this->cargo_payment;
00682   }
00683 
00684   if (this->IsEngineCountable()) {
00685     Company::Get(this->owner)->num_engines[this->engine_type]--;
00686     if (this->owner == _local_company) InvalidateAutoreplaceWindow(this->engine_type, this->group_id);
00687 
00688     DeleteGroupHighlightOfVehicle(this);
00689     if (Group::IsValidID(this->group_id)) Group::Get(this->group_id)->num_engines[this->engine_type]--;
00690     if (this->IsPrimaryVehicle()) DecreaseGroupNumVehicle(this->group_id);
00691   }
00692 
00693   if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) {
00694     Aircraft *a = Aircraft::From(this);
00695     Station *st = GetTargetAirportIfValid(a);
00696     if (st != NULL) {
00697       const AirportFTA *layout = st->airport.GetFTA()->layout;
00698       CLRBITS(st->airport.flags, layout[a->previous_pos].block | layout[a->pos].block);
00699     }
00700   }
00701 
00702 
00703   if (this->type == VEH_ROAD && this->IsPrimaryVehicle()) {
00704     RoadVehicle *v = RoadVehicle::From(this);
00705     if (!(v->vehstatus & VS_CRASHED) && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
00706       /* Leave the drive through roadstop, when you have not already left it. */
00707       RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
00708     }
00709   }
00710 
00711   if (this->Previous() == NULL) {
00712     InvalidateWindowData(WC_VEHICLE_DEPOT, this->tile);
00713   }
00714 
00715   if (this->IsPrimaryVehicle()) {
00716     DeleteWindowById(WC_VEHICLE_VIEW, this->index);
00717     DeleteWindowById(WC_VEHICLE_ORDERS, this->index);
00718     DeleteWindowById(WC_VEHICLE_REFIT, this->index);
00719     DeleteWindowById(WC_VEHICLE_DETAILS, this->index);
00720     DeleteWindowById(WC_VEHICLE_TIMETABLE, this->index);
00721     SetWindowDirty(WC_COMPANY, this->owner);
00722     OrderBackup::ClearVehicle(this);
00723   }
00724   InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
00725 
00726   this->cargo.Truncate(0);
00727   DeleteVehicleOrders(this);
00728   DeleteDepotHighlightOfVehicle(this);
00729 
00730   extern void StopGlobalFollowVehicle(const Vehicle *v);
00731   StopGlobalFollowVehicle(this);
00732 
00733   ReleaseDisastersTargetingVehicle(this->index);
00734 }
00735 
00736 Vehicle::~Vehicle()
00737 {
00738   free(this->name);
00739 
00740   if (CleaningPool()) return;
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) ? 184 : (_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 
00907 void ViewportAddVehicles(DrawPixelInfo *dpi)
00908 {
00909   /* The bounding rectangle */
00910   const int l = dpi->left;
00911   const int r = dpi->left + dpi->width;
00912   const int t = dpi->top;
00913   const int b = dpi->top + dpi->height;
00914 
00915   /* The hash area to scan */
00916   int xl, xu, yl, yu;
00917 
00918   if (dpi->width + 70 < (1 << (7 + 6))) {
00919     xl = GB(l - 70, 7, 6);
00920     xu = GB(r,      7, 6);
00921   } else {
00922     /* scan whole hash row */
00923     xl = 0;
00924     xu = 0x3F;
00925   }
00926 
00927   if (dpi->height + 70 < (1 << (6 + 6))) {
00928     yl = GB(t - 70, 6, 6) << 6;
00929     yu = GB(b,      6, 6) << 6;
00930   } else {
00931     /* scan whole column */
00932     yl = 0;
00933     yu = 0x3F << 6;
00934   }
00935 
00936   for (int y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
00937     for (int x = xl;; x = (x + 1) & 0x3F) {
00938       const Vehicle *v = _vehicle_position_hash[x + y]; // already masked & 0xFFF
00939 
00940       while (v != NULL) {
00941         if (!(v->vehstatus & VS_HIDDEN) &&
00942             l <= v->coord.right &&
00943             t <= v->coord.bottom &&
00944             r >= v->coord.left &&
00945             b >= v->coord.top) {
00946           DoDrawVehicle(v);
00947         }
00948         v = v->next_hash;
00949       }
00950 
00951       if (x == xu) break;
00952     }
00953 
00954     if (y == yu) break;
00955   }
00956 }
00957 
00958 Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y)
00959 {
00960   Vehicle *found = NULL, *v;
00961   uint dist, best_dist = UINT_MAX;
00962 
00963   if ((uint)(x -= vp->left) >= (uint)vp->width || (uint)(y -= vp->top) >= (uint)vp->height) return NULL;
00964 
00965   x = ScaleByZoom(x, vp->zoom) + vp->virtual_left;
00966   y = ScaleByZoom(y, vp->zoom) + vp->virtual_top;
00967 
00968   FOR_ALL_VEHICLES(v) {
00969     if ((v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0 &&
00970         x >= v->coord.left && x <= v->coord.right &&
00971         y >= v->coord.top && y <= v->coord.bottom) {
00972 
00973       dist = max(
00974         abs(((v->coord.left + v->coord.right) >> 1) - x),
00975         abs(((v->coord.top + v->coord.bottom) >> 1) - y)
00976       );
00977 
00978       if (dist < best_dist) {
00979         found = v;
00980         best_dist = dist;
00981       }
00982     }
00983   }
00984 
00985   return found;
00986 }
00987 
00988 void DecreaseVehicleValue(Vehicle *v)
00989 {
00990   v->value -= v->value >> 8;
00991   SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
00992 }
00993 
00994 static const byte _breakdown_chance[64] = {
00995     3,   3,   3,   3,   3,   3,   3,   3,
00996     4,   4,   5,   5,   6,   6,   7,   7,
00997     8,   8,   9,   9,  10,  10,  11,  11,
00998    12,  13,  13,  13,  13,  14,  15,  16,
00999    17,  19,  21,  25,  28,  31,  34,  37,
01000    40,  44,  48,  52,  56,  60,  64,  68,
01001    72,  80,  90, 100, 110, 120, 130, 140,
01002   150, 170, 190, 210, 230, 250, 250, 250,
01003 };
01004 
01005 void CheckVehicleBreakdown(Vehicle *v)
01006 {
01007   int rel, rel_old;
01008 
01009   /* decrease reliability */
01010   v->reliability = rel = max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
01011   if ((rel_old >> 8) != (rel >> 8)) SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
01012 
01013   if (v->breakdown_ctr != 0 || (v->vehstatus & VS_STOPPED) ||
01014       _settings_game.difficulty.vehicle_breakdowns < 1 ||
01015       v->cur_speed < 5 || _game_mode == GM_MENU) {
01016     return;
01017   }
01018 
01019   uint32 r = Random();
01020 
01021   /* increase chance of failure */
01022   int chance = v->breakdown_chance + 1;
01023   if (Chance16I(1, 25, r)) chance += 25;
01024   v->breakdown_chance = min(255, chance);
01025 
01026   /* calculate reliability value to use in comparison */
01027   rel = v->reliability;
01028   if (v->type == VEH_SHIP) rel += 0x6666;
01029 
01030   /* reduced breakdowns? */
01031   if (_settings_game.difficulty.vehicle_breakdowns == 1) rel += 0x6666;
01032 
01033   /* check if to break down */
01034   if (_breakdown_chance[(uint)min(rel, 0xffff) >> 10] <= v->breakdown_chance) {
01035     v->breakdown_ctr    = GB(r, 16, 6) + 0x3F;
01036     v->breakdown_delay  = GB(r, 24, 7) + 0x80;
01037     v->breakdown_chance = 0;
01038   }
01039 }
01040 
01047 bool Vehicle::HandleBreakdown()
01048 {
01049   /* Possible states for Vehicle::breakdown_ctr
01050    * 0  - vehicle is running normally
01051    * 1  - vehicle is currently broken down
01052    * 2  - vehicle is going to break down now
01053    * >2 - vehicle is counting down to the actual breakdown event */
01054   switch (this->breakdown_ctr) {
01055     case 0:
01056       return false;
01057 
01058     case 2:
01059       this->breakdown_ctr = 1;
01060 
01061       if (this->breakdowns_since_last_service != 255) {
01062         this->breakdowns_since_last_service++;
01063       }
01064 
01065       this->MarkDirty();
01066       SetWindowDirty(WC_VEHICLE_VIEW, this->index);
01067       SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
01068 
01069       if (this->type == VEH_AIRCRAFT) {
01070         /* Aircraft just need this flag, the rest is handled elsewhere */
01071         this->vehstatus |= VS_AIRCRAFT_BROKEN;
01072       } else {
01073         this->cur_speed = 0;
01074 
01075         if (!PlayVehicleSound(this, VSE_BREAKDOWN)) {
01076           SndPlayVehicleFx((_settings_game.game_creation.landscape != LT_TOYLAND) ?
01077             (this->type == VEH_TRAIN ? SND_10_TRAIN_BREAKDOWN : SND_0F_VEHICLE_BREAKDOWN) :
01078             (this->type == VEH_TRAIN ? SND_3A_COMEDY_BREAKDOWN_2 : SND_35_COMEDY_BREAKDOWN), this);
01079         }
01080 
01081         if (!(this->vehstatus & VS_HIDDEN)) {
01082           EffectVehicle *u = CreateEffectVehicleRel(this, 4, 4, 5, EV_BREAKDOWN_SMOKE);
01083           if (u != NULL) u->animation_state = this->breakdown_delay * 2;
01084         }
01085       }
01086       /* FALL THROUGH */
01087     case 1:
01088       /* Aircraft breakdowns end only when arriving at the airport */
01089       if (this->type == VEH_AIRCRAFT) return false;
01090 
01091       /* For trains this function is called twice per tick, so decrease v->breakdown_delay at half the rate */
01092       if ((this->tick_counter & (this->type == VEH_TRAIN ? 3 : 1)) == 0) {
01093         if (--this->breakdown_delay == 0) {
01094           this->breakdown_ctr = 0;
01095           this->MarkDirty();
01096           SetWindowDirty(WC_VEHICLE_VIEW, this->index);
01097         }
01098       }
01099       return true;
01100 
01101     default:
01102       if (!this->current_order.IsType(OT_LOADING)) this->breakdown_ctr--;
01103       return false;
01104   }
01105 }
01106 
01111 void AgeVehicle(Vehicle *v)
01112 {
01113   if (v->age < MAX_DAY) v->age++;
01114 
01115   int age = v->age - v->max_age;
01116   if (age == DAYS_IN_LEAP_YEAR * 0 || age == DAYS_IN_LEAP_YEAR * 1 ||
01117       age == DAYS_IN_LEAP_YEAR * 2 || age == DAYS_IN_LEAP_YEAR * 3 || age == DAYS_IN_LEAP_YEAR * 4) {
01118     v->reliability_spd_dec <<= 1;
01119   }
01120 
01121   SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
01122 
01123   /* Don't warn about non-primary or not ours vehicles or vehicles that are crashed */
01124   if (v->Previous() != NULL || v->owner != _local_company || (v->vehstatus & VS_CRASHED) != 0) return;
01125 
01126   /* Don't warn if a renew is active */
01127   if (Company::Get(v->owner)->settings.engine_renew && Engine::Get(v->engine_type)->company_avail != 0) return;
01128 
01129   StringID str;
01130   if (age == -DAYS_IN_LEAP_YEAR) {
01131     str = STR_NEWS_VEHICLE_IS_GETTING_OLD;
01132   } else if (age == 0) {
01133     str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD;
01134   } else if (age > 0 && (age % DAYS_IN_LEAP_YEAR) == 0) {
01135     str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND;
01136   } else {
01137     return;
01138   }
01139 
01140   SetDParam(0, v->index);
01141   AddVehicleNewsItem(str, NS_ADVICE, v->index);
01142 }
01143 
01150 uint8 CalcPercentVehicleFilled(const Vehicle *v, StringID *colour)
01151 {
01152   int count = 0;
01153   int max = 0;
01154   int cars = 0;
01155   int unloading = 0;
01156   bool loading = false;
01157 
01158   const Vehicle *u = v;
01159   /* The station may be NULL when the (colour) string does not need to be set. */
01160   const Station *st = Station::GetIfValid(v->last_station_visited);
01161   assert(colour == NULL || st != NULL);
01162 
01163   /* Count up max and used */
01164   for (; v != NULL; v = v->Next()) {
01165     count += v->cargo.Count();
01166     max += v->cargo_cap;
01167     if (v->cargo_cap != 0 && colour != NULL) {
01168       unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0;
01169       loading |= !(u->current_order.GetLoadType() & OLFB_NO_LOAD) && st->goods[v->cargo_type].days_since_pickup != 255;
01170       cars++;
01171     }
01172   }
01173 
01174   if (colour != NULL) {
01175     if (unloading == 0 && loading) {
01176       *colour = STR_PERCENT_UP;
01177     } else if (cars == unloading || !loading) {
01178       *colour = STR_PERCENT_DOWN;
01179     } else {
01180       *colour = STR_PERCENT_UP_DOWN;
01181     }
01182   }
01183 
01184   /* Train without capacity */
01185   if (max == 0) return 100;
01186 
01187   /* Return the percentage */
01188   return (count * 100) / max;
01189 }
01190 
01191 void VehicleEnterDepot(Vehicle *v)
01192 {
01193   /* Always work with the front of the vehicle */
01194   assert(v == v->First());
01195 
01196   switch (v->type) {
01197     case VEH_TRAIN: {
01198       Train *t = Train::From(v);
01199       SetWindowClassesDirty(WC_TRAINS_LIST);
01200       /* Clear path reservation */
01201       SetDepotReservation(t->tile, false);
01202       if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(t->tile);
01203 
01204       UpdateSignalsOnSegment(t->tile, INVALID_DIAGDIR, t->owner);
01205       t->wait_counter = 0;
01206       t->force_proceed = TFP_NONE;
01207       ClrBit(t->flags, VRF_TOGGLE_REVERSE);
01208       t->ConsistChanged(true);
01209       break;
01210     }
01211 
01212     case VEH_ROAD:
01213       SetWindowClassesDirty(WC_ROADVEH_LIST);
01214       break;
01215 
01216     case VEH_SHIP: {
01217       SetWindowClassesDirty(WC_SHIPS_LIST);
01218       Ship *ship = Ship::From(v);
01219       ship->state = TRACK_BIT_DEPOT;
01220       ship->UpdateCache();
01221       ship->UpdateViewport(true, true);
01222       SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
01223       break;
01224     }
01225 
01226     case VEH_AIRCRAFT:
01227       SetWindowClassesDirty(WC_AIRCRAFT_LIST);
01228       HandleAircraftEnterHangar(Aircraft::From(v));
01229       break;
01230     default: NOT_REACHED();
01231   }
01232   SetWindowDirty(WC_VEHICLE_VIEW, v->index);
01233 
01234   if (v->type != VEH_TRAIN) {
01235     /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
01236      * 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 */
01237     InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
01238   }
01239   SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
01240 
01241   v->vehstatus |= VS_HIDDEN;
01242   v->cur_speed = 0;
01243 
01244   VehicleServiceInDepot(v);
01245 
01246   TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
01247 
01248   if (v->current_order.IsType(OT_GOTO_DEPOT)) {
01249     SetWindowDirty(WC_VEHICLE_VIEW, v->index);
01250 
01251     const Order *real_order = v->GetNextManualOrder(v->cur_order_index);
01252     Order t = v->current_order;
01253     v->current_order.MakeDummy();
01254 
01255     /* Test whether we are heading for this depot. If not, do nothing.
01256      * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
01257     if ((t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) &&
01258         real_order != NULL && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) &&
01259         (v->type == VEH_AIRCRAFT ? t.GetDestination() != GetStationIndex(v->tile) : v->dest_tile != v->tile)) {
01260       /* We are heading for another depot, keep driving. */
01261       return;
01262     }
01263 
01264     if (t.IsRefit()) {
01265       Backup<CompanyByte> cur_company(_current_company, v->owner, FILE_LINE);
01266       CommandCost cost = DoCommand(v->tile, v->index, t.GetRefitCargo() | t.GetRefitSubtype() << 8, DC_EXEC, GetCmdRefitVeh(v));
01267       cur_company.Restore();
01268 
01269       if (cost.Failed()) {
01270         _vehicles_to_autoreplace[v] = false;
01271         if (v->owner == _local_company) {
01272           /* Notify the user that we stopped the vehicle */
01273           SetDParam(0, v->index);
01274           AddVehicleNewsItem(STR_NEWS_ORDER_REFIT_FAILED, NS_ADVICE, v->index);
01275         }
01276       } else if (cost.GetCost() != 0) {
01277         v->profit_this_year -= cost.GetCost() << 8;
01278         if (v->owner == _local_company) {
01279           ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
01280         }
01281       }
01282     }
01283 
01284     if (t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
01285       /* Part of orders */
01286       v->DeleteUnreachedAutoOrders();
01287       UpdateVehicleTimetable(v, true);
01288       v->IncrementOrderIndex();
01289     }
01290     if (t.GetDepotActionType() & ODATFB_HALT) {
01291       /* Vehicles are always stopped on entering depots. Do not restart this one. */
01292       _vehicles_to_autoreplace[v] = false;
01293       if (v->owner == _local_company) {
01294         SetDParam(0, v->index);
01295         AddVehicleNewsItem(STR_NEWS_TRAIN_IS_WAITING + v->type, NS_ADVICE, v->index);
01296       }
01297       AI::NewEvent(v->owner, new AIEventVehicleWaitingInDepot(v->index));
01298     }
01299   }
01300 }
01301 
01302 
01310 void VehicleMove(Vehicle *v, bool update_viewport)
01311 {
01312   int img = v->cur_image;
01313   Point pt = RemapCoords(v->x_pos + v->x_offs, v->y_pos + v->y_offs, v->z_pos);
01314   const Sprite *spr = GetSprite(img, ST_NORMAL);
01315 
01316   pt.x += spr->x_offs;
01317   pt.y += spr->y_offs;
01318 
01319   UpdateVehiclePosHash(v, pt.x, pt.y);
01320 
01321   Rect old_coord = v->coord;
01322   v->coord.left   = pt.x;
01323   v->coord.top    = pt.y;
01324   v->coord.right  = pt.x + spr->width + 2;
01325   v->coord.bottom = pt.y + spr->height + 2;
01326 
01327   if (update_viewport) {
01328     MarkAllViewportsDirty(
01329       min(old_coord.left,   v->coord.left),
01330       min(old_coord.top,    v->coord.top),
01331       max(old_coord.right,  v->coord.right) + 1,
01332       max(old_coord.bottom, v->coord.bottom) + 1
01333     );
01334   }
01335 }
01336 
01345 void MarkSingleVehicleDirty(const Vehicle *v)
01346 {
01347   MarkAllViewportsDirty(v->coord.left, v->coord.top, v->coord.right + 1, v->coord.bottom + 1);
01348 }
01349 
01355 GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
01356 {
01357   static const int8 _delta_coord[16] = {
01358     -1,-1,-1, 0, 1, 1, 1, 0, /* x */
01359     -1, 0, 1, 1, 1, 0,-1,-1, /* y */
01360   };
01361 
01362   int x = v->x_pos + _delta_coord[v->direction];
01363   int y = v->y_pos + _delta_coord[v->direction + 8];
01364 
01365   GetNewVehiclePosResult gp;
01366   gp.x = x;
01367   gp.y = y;
01368   gp.old_tile = v->tile;
01369   gp.new_tile = TileVirtXY(x, y);
01370   return gp;
01371 }
01372 
01373 static const Direction _new_direction_table[] = {
01374   DIR_N,  DIR_NW, DIR_W,
01375   DIR_NE, DIR_SE, DIR_SW,
01376   DIR_E,  DIR_SE, DIR_S
01377 };
01378 
01379 Direction GetDirectionTowards(const Vehicle *v, int x, int y)
01380 {
01381   int i = 0;
01382 
01383   if (y >= v->y_pos) {
01384     if (y != v->y_pos) i += 3;
01385     i += 3;
01386   }
01387 
01388   if (x >= v->x_pos) {
01389     if (x != v->x_pos) i++;
01390     i++;
01391   }
01392 
01393   Direction dir = v->direction;
01394 
01395   DirDiff dirdiff = DirDifference(_new_direction_table[i], dir);
01396   if (dirdiff == DIRDIFF_SAME) return dir;
01397   return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
01398 }
01399 
01409 VehicleEnterTileStatus VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
01410 {
01411   return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
01412 }
01413 
01421 FreeUnitIDGenerator::FreeUnitIDGenerator(VehicleType type, CompanyID owner) : cache(NULL), maxid(0), curid(0)
01422 {
01423   /* Find maximum */
01424   const Vehicle *v;
01425   FOR_ALL_VEHICLES(v) {
01426     if (v->type == type && v->owner == owner) {
01427       this->maxid = max<UnitID>(this->maxid, v->unitnumber);
01428     }
01429   }
01430 
01431   if (this->maxid == 0) return;
01432 
01433   /* Reserving 'maxid + 2' because we need:
01434    * - space for the last item (with v->unitnumber == maxid)
01435    * - one free slot working as loop terminator in FreeUnitIDGenerator::NextID() */
01436   this->cache = CallocT<bool>(this->maxid + 2);
01437 
01438   /* Fill the cache */
01439   FOR_ALL_VEHICLES(v) {
01440     if (v->type == type && v->owner == owner) {
01441       this->cache[v->unitnumber] = true;
01442     }
01443   }
01444 }
01445 
01447 UnitID FreeUnitIDGenerator::NextID()
01448 {
01449   if (this->maxid <= this->curid) return ++this->curid;
01450 
01451   while (this->cache[++this->curid]) { } // it will stop, we reserved more space than needed
01452 
01453   return this->curid;
01454 }
01455 
01461 UnitID GetFreeUnitNumber(VehicleType type)
01462 {
01463   /* Check whether it is allowed to build another vehicle. */
01464   uint max_veh;
01465   switch (type) {
01466     case VEH_TRAIN:    max_veh = _settings_game.vehicle.max_trains;   break;
01467     case VEH_ROAD:     max_veh = _settings_game.vehicle.max_roadveh;  break;
01468     case VEH_SHIP:     max_veh = _settings_game.vehicle.max_ships;    break;
01469     case VEH_AIRCRAFT: max_veh = _settings_game.vehicle.max_aircraft; break;
01470     default: NOT_REACHED();
01471   }
01472 
01473   uint amounts[4];
01474   CountCompanyVehicles(_current_company, amounts);
01475   assert((uint)type < lengthof(amounts));
01476   if (amounts[type] >= max_veh) return UINT16_MAX; // Currently already at the limit, no room to make a new one.
01477 
01478   FreeUnitIDGenerator gen(type, _current_company);
01479 
01480   return gen.NextID();
01481 }
01482 
01483 
01492 bool CanBuildVehicleInfrastructure(VehicleType type)
01493 {
01494   assert(IsCompanyBuildableVehicleType(type));
01495 
01496   if (!Company::IsValidID(_local_company)) return false;
01497   if (!_settings_client.gui.disable_unsuitable_building) return true;
01498 
01499   UnitID max;
01500   switch (type) {
01501     case VEH_TRAIN:    max = _settings_game.vehicle.max_trains; break;
01502     case VEH_ROAD:     max = _settings_game.vehicle.max_roadveh; break;
01503     case VEH_SHIP:     max = _settings_game.vehicle.max_ships; break;
01504     case VEH_AIRCRAFT: max = _settings_game.vehicle.max_aircraft; break;
01505     default: NOT_REACHED();
01506   }
01507 
01508   /* We can build vehicle infrastructure when we may build the vehicle type */
01509   if (max > 0) {
01510     /* Can we actually build the vehicle type? */
01511     const Engine *e;
01512     FOR_ALL_ENGINES_OF_TYPE(e, type) {
01513       if (HasBit(e->company_avail, _local_company)) return true;
01514     }
01515     return false;
01516   }
01517 
01518   /* We should be able to build infrastructure when we have the actual vehicle type */
01519   const Vehicle *v;
01520   FOR_ALL_VEHICLES(v) {
01521     if (v->owner == _local_company && v->type == type) return true;
01522   }
01523 
01524   return false;
01525 }
01526 
01527 
01535 LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v)
01536 {
01537   CargoID cargo_type = v == NULL ? (CargoID)CT_INVALID : v->cargo_type;
01538   const Engine *e = Engine::Get(engine_type);
01539   switch (e->type) {
01540     default: NOT_REACHED();
01541     case VEH_TRAIN:
01542       if (v != NULL && parent_engine_type != INVALID_ENGINE && (UsesWagonOverride(v) || (Train::From(v)->IsArticulatedPart() && e->u.rail.railveh_type != RAILVEH_WAGON))) {
01543         /* Wagonoverrides use the colour scheme of the front engine.
01544          * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */
01545         engine_type = parent_engine_type;
01546         e = Engine::Get(engine_type);
01547         /* Note: Luckily cargo_type is not needed for engines */
01548       }
01549 
01550       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
01551       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
01552       if (e->u.rail.railveh_type == RAILVEH_WAGON) {
01553         if (!CargoSpec::Get(cargo_type)->is_freight) {
01554           if (parent_engine_type == INVALID_ENGINE) {
01555             return LS_PASSENGER_WAGON_STEAM;
01556           } else {
01557             switch (RailVehInfo(parent_engine_type)->engclass) {
01558               default: NOT_REACHED();
01559               case EC_STEAM:    return LS_PASSENGER_WAGON_STEAM;
01560               case EC_DIESEL:   return LS_PASSENGER_WAGON_DIESEL;
01561               case EC_ELECTRIC: return LS_PASSENGER_WAGON_ELECTRIC;
01562               case EC_MONORAIL: return LS_PASSENGER_WAGON_MONORAIL;
01563               case EC_MAGLEV:   return LS_PASSENGER_WAGON_MAGLEV;
01564             }
01565           }
01566         } else {
01567           return LS_FREIGHT_WAGON;
01568         }
01569       } else {
01570         bool is_mu = HasBit(e->info.misc_flags, EF_RAIL_IS_MU);
01571 
01572         switch (e->u.rail.engclass) {
01573           default: NOT_REACHED();
01574           case EC_STEAM:    return LS_STEAM;
01575           case EC_DIESEL:   return is_mu ? LS_DMU : LS_DIESEL;
01576           case EC_ELECTRIC: return is_mu ? LS_EMU : LS_ELECTRIC;
01577           case EC_MONORAIL: return LS_MONORAIL;
01578           case EC_MAGLEV:   return LS_MAGLEV;
01579         }
01580       }
01581 
01582     case VEH_ROAD:
01583       /* Always use the livery of the front */
01584       if (v != NULL && parent_engine_type != INVALID_ENGINE) {
01585         engine_type = parent_engine_type;
01586         e = Engine::Get(engine_type);
01587         cargo_type = v->First()->cargo_type;
01588       }
01589       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
01590       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
01591 
01592       /* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */
01593       if (HasBit(e->info.misc_flags, EF_ROAD_TRAM)) {
01594         /* Tram */
01595         return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
01596       } else {
01597         /* Bus or truck */
01598         return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_BUS : LS_TRUCK;
01599       }
01600 
01601     case VEH_SHIP:
01602       if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType();
01603       if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo
01604       return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
01605 
01606     case VEH_AIRCRAFT:
01607       switch (e->u.air.subtype) {
01608         case AIR_HELI: return LS_HELICOPTER;
01609         case AIR_CTOL: return LS_SMALL_PLANE;
01610         case AIR_CTOL | AIR_FAST: return LS_LARGE_PLANE;
01611         default: NOT_REACHED();
01612       }
01613   }
01614 }
01615 
01625 const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, byte livery_setting)
01626 {
01627   const Company *c = Company::Get(company);
01628   LiveryScheme scheme = LS_DEFAULT;
01629 
01630   /* The default livery is always available for use, but its in_use flag determines
01631    * whether any _other_ liveries are in use. */
01632   if (c->livery[LS_DEFAULT].in_use && (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company))) {
01633     /* Determine the livery scheme to use */
01634     scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v);
01635 
01636     /* Switch back to the default scheme if the resolved scheme is not in use */
01637     if (!c->livery[scheme].in_use) scheme = LS_DEFAULT;
01638   }
01639 
01640   return &c->livery[scheme];
01641 }
01642 
01643 
01644 static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v)
01645 {
01646   PaletteID map = (v != NULL) ? v->colourmap : PAL_NONE;
01647 
01648   /* Return cached value if any */
01649   if (map != PAL_NONE) return map;
01650 
01651   const Engine *e = Engine::Get(engine_type);
01652 
01653   /* Check if we should use the colour map callback */
01654   if (HasBit(e->info.callback_mask, CBM_VEHICLE_COLOUR_REMAP)) {
01655     uint16 callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
01656     /* Failure means "use the default two-colour" */
01657     if (callback != CALLBACK_FAILED) {
01658       assert_compile(PAL_NONE == 0); // Returning 0x4000 (resp. 0xC000) conincidences with default value (PAL_NONE)
01659       map = GB(callback, 0, 14);
01660       /* If bit 14 is set, then the company colours are applied to the
01661        * map else it's returned as-is. */
01662       if (!HasBit(callback, 14)) {
01663         /* Update cache */
01664         if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
01665         return map;
01666       }
01667     }
01668   }
01669 
01670   bool twocc = HasBit(e->info.misc_flags, EF_USES_2CC);
01671 
01672   if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START;
01673 
01674   /* Spectator has news shown too, but has invalid company ID - as well as dedicated server */
01675   if (!Company::IsValidID(company)) return map;
01676 
01677   const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries);
01678 
01679   map += livery->colour1;
01680   if (twocc) map += livery->colour2 * 16;
01681 
01682   /* Update cache */
01683   if (v != NULL) const_cast<Vehicle *>(v)->colourmap = map;
01684   return map;
01685 }
01686 
01693 PaletteID GetEnginePalette(EngineID engine_type, CompanyID company)
01694 {
01695   return GetEngineColourMap(engine_type, company, INVALID_ENGINE, NULL);
01696 }
01697 
01703 PaletteID GetVehiclePalette(const Vehicle *v)
01704 {
01705   if (v->IsGroundVehicle()) {
01706     return GetEngineColourMap(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v);
01707   }
01708 
01709   return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
01710 }
01711 
01720 uint GetVehicleCapacity(const Vehicle *v, uint16 *mail_capacity)
01721 {
01722   if (mail_capacity != NULL) *mail_capacity = 0;
01723   const Engine *e = Engine::Get(v->engine_type);
01724 
01725   if (!e->CanCarryCargo()) return 0;
01726 
01727   if (mail_capacity != NULL && e->type == VEH_AIRCRAFT && IsCargoInClass(v->cargo_type, CC_PASSENGERS)) {
01728     *mail_capacity = GetVehicleProperty(v, PROP_AIRCRAFT_MAIL_CAPACITY, e->u.air.mail_capacity);
01729   }
01730   CargoID default_cargo = e->GetDefaultCargoType();
01731 
01732   /* Check the refit capacity callback if we are not in the default configuration.
01733    * Note: This might change to become more consistent/flexible/sane, esp. when default cargo is first refittable. */
01734   if (HasBit(e->info.callback_mask, CBM_VEHICLE_REFIT_CAPACITY) &&
01735       (default_cargo != v->cargo_type || v->cargo_subtype != 0)) {
01736     uint16 callback = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, v->engine_type, v);
01737     if (callback != CALLBACK_FAILED) return callback;
01738   }
01739 
01740   /* Get capacity according to property resp. CB */
01741   uint capacity;
01742   switch (e->type) {
01743     case VEH_TRAIN:    capacity = GetVehicleProperty(v, PROP_TRAIN_CARGO_CAPACITY,        e->u.rail.capacity); break;
01744     case VEH_ROAD:     capacity = GetVehicleProperty(v, PROP_ROADVEH_CARGO_CAPACITY,      e->u.road.capacity); break;
01745     case VEH_SHIP:     capacity = GetVehicleProperty(v, PROP_SHIP_CARGO_CAPACITY,         e->u.ship.capacity); break;
01746     case VEH_AIRCRAFT: capacity = GetVehicleProperty(v, PROP_AIRCRAFT_PASSENGER_CAPACITY, e->u.air.passenger_capacity); break;
01747     default: NOT_REACHED();
01748   }
01749 
01750   /* Apply multipliers depending on cargo- and vehicletype.
01751    * Note: This might change to become more consistent/flexible. */
01752   if (e->type != VEH_SHIP) {
01753     if (e->type == VEH_AIRCRAFT) {
01754       if (!IsCargoInClass(v->cargo_type, CC_PASSENGERS)) {
01755         capacity += GetVehicleProperty(v, PROP_AIRCRAFT_MAIL_CAPACITY, e->u.air.mail_capacity);
01756       }
01757       if (v->cargo_type == CT_MAIL) return capacity;
01758     } else {
01759       switch (default_cargo) {
01760         case CT_PASSENGERS: break;
01761         case CT_MAIL:
01762         case CT_GOODS: capacity *= 2; break;
01763         default:       capacity *= 4; break;
01764       }
01765     }
01766     switch (v->cargo_type) {
01767       case CT_PASSENGERS: break;
01768       case CT_MAIL:
01769       case CT_GOODS: capacity /= 2; break;
01770       default:       capacity /= 4; break;
01771     }
01772   }
01773 
01774   return capacity;
01775 }
01776 
01780 void Vehicle::DeleteUnreachedAutoOrders()
01781 {
01782   const Order *order = this->GetOrder(this->cur_order_index);
01783   while (order != NULL && order->IsType(OT_AUTOMATIC)) {
01784     /* Delete order effectively deletes order, so get the next before deleting it. */
01785     order = order->next;
01786     DeleteOrder(this, this->cur_order_index);
01787   }
01788 }
01789 
01790 void Vehicle::BeginLoading()
01791 {
01792   assert(IsTileType(tile, MP_STATION) || type == VEH_SHIP);
01793 
01794   if (this->current_order.IsType(OT_GOTO_STATION) &&
01795       this->current_order.GetDestination() == this->last_station_visited) {
01796     this->DeleteUnreachedAutoOrders();
01797 
01798     /* Now cur_order_index points to the destination station, and we can start loading */
01799     this->current_order.MakeLoading(true);
01800     UpdateVehicleTimetable(this, true);
01801 
01802     /* Furthermore add the Non Stop flag to mark that this station
01803      * is the actual destination of the vehicle, which is (for example)
01804      * necessary to be known for HandleTrainLoading to determine
01805      * whether the train is lost or not; not marking a train lost
01806      * that arrives at random stations is bad. */
01807     this->current_order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
01808 
01809   } else {
01810     /* We weren't scheduled to stop here. Insert an automatic order
01811      * to show that we are stopping here, but only do that if the order
01812      * list isn't empty. */
01813     Order *in_list = this->GetOrder(this->cur_order_index);
01814     if (in_list != NULL && this->orders.list->GetNumOrders() < MAX_VEH_ORDER_ID &&
01815         (!in_list->IsType(OT_AUTOMATIC) ||
01816         in_list->GetDestination() != this->last_station_visited)) {
01817       Order *auto_order = new Order();
01818       auto_order->MakeAutomatic(this->last_station_visited);
01819       InsertOrder(this, auto_order, this->cur_order_index);
01820       if (this->cur_order_index > 0) --this->cur_order_index;
01821     }
01822     this->current_order.MakeLoading(false);
01823   }
01824 
01825   Station::Get(this->last_station_visited)->loading_vehicles.push_back(this);
01826 
01827   PrepareUnload(this);
01828 
01829   SetWindowDirty(GetWindowClassForVehicleType(this->type), this->owner);
01830   SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
01831   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
01832   SetWindowDirty(WC_STATION_VIEW, this->last_station_visited);
01833 
01834   Station::Get(this->last_station_visited)->MarkTilesDirty(true);
01835   this->cur_speed = 0;
01836   this->MarkDirty();
01837 }
01838 
01839 void Vehicle::LeaveStation()
01840 {
01841   assert(current_order.IsType(OT_LOADING));
01842 
01843   delete this->cargo_payment;
01844 
01845   /* Only update the timetable if the vehicle was supposed to stop here. */
01846   if (current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE) UpdateVehicleTimetable(this, false);
01847 
01848   current_order.MakeLeaveStation();
01849   Station *st = Station::Get(this->last_station_visited);
01850   st->loading_vehicles.remove(this);
01851 
01852   HideFillingPercent(&this->fill_percent_te_id);
01853 
01854   if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) {
01855     /* Trigger station animation (trains only) */
01856     if (IsTileType(this->tile, MP_STATION)) TriggerStationAnimation(st, this->tile, SAT_TRAIN_DEPARTS);
01857 
01858     SetBit(Train::From(this)->flags, VRF_LEAVING_STATION);
01859   }
01860 }
01861 
01862 
01868 void Vehicle::HandleLoading(bool mode)
01869 {
01870   switch (this->current_order.GetType()) {
01871     case OT_LOADING: {
01872       uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0);
01873 
01874       /* Not the first call for this tick, or still loading */
01875       if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) ||
01876           (_settings_game.order.timetabling && this->current_order_time < wait_time)) return;
01877 
01878       this->PlayLeaveStationSound();
01879 
01880       this->LeaveStation();
01881 
01882       break;
01883     }
01884 
01885     case OT_DUMMY: break;
01886 
01887     default: return;
01888   }
01889 
01890   this->IncrementOrderIndex();
01891 }
01892 
01899 CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command)
01900 {
01901   CommandCost ret = CheckOwnership(this->owner);
01902   if (ret.Failed()) return ret;
01903 
01904   if (this->vehstatus & VS_CRASHED) return CMD_ERROR;
01905   if (this->IsStoppedInDepot()) return CMD_ERROR;
01906 
01907   if (this->current_order.IsType(OT_GOTO_DEPOT)) {
01908     bool halt_in_depot = (this->current_order.GetDepotActionType() & ODATFB_HALT) != 0;
01909     if (!!(command & DEPOT_SERVICE) == halt_in_depot) {
01910       /* We called with a different DEPOT_SERVICE setting.
01911        * Now we change the setting to apply the new one and let the vehicle head for the same depot.
01912        * Note: the if is (true for requesting service == true for ordered to stop in depot)          */
01913       if (flags & DC_EXEC) {
01914         this->current_order.SetDepotOrderType(ODTF_MANUAL);
01915         this->current_order.SetDepotActionType(halt_in_depot ? ODATF_SERVICE_ONLY : ODATFB_HALT);
01916         SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
01917       }
01918       return CommandCost();
01919     }
01920 
01921     if (command & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
01922     if (flags & DC_EXEC) {
01923       /* If the orders to 'goto depot' are in the orders list (forced servicing),
01924        * then skip to the next order; effectively cancelling this forced service */
01925       if (this->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) this->IncrementOrderIndex();
01926 
01927       this->current_order.MakeDummy();
01928       SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
01929     }
01930     return CommandCost();
01931   }
01932 
01933   TileIndex location;
01934   DestinationID destination;
01935   bool reverse;
01936   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};
01937   if (!this->FindClosestDepot(&location, &destination, &reverse)) return_cmd_error(no_depot[this->type]);
01938 
01939   if (flags & DC_EXEC) {
01940     if (this->current_order.IsType(OT_LOADING)) this->LeaveStation();
01941 
01942     this->dest_tile = location;
01943     this->current_order.MakeGoToDepot(destination, ODTF_MANUAL);
01944     if (!(command & DEPOT_SERVICE)) this->current_order.SetDepotActionType(ODATFB_HALT);
01945     SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
01946 
01947     /* If there is no depot in front, reverse automatically (trains only) */
01948     if (this->type == VEH_TRAIN && reverse) DoCommand(this->tile, this->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
01949 
01950     if (this->type == VEH_AIRCRAFT) {
01951       Aircraft *a = Aircraft::From(this);
01952       if (a->state == FLYING && a->targetairport != destination) {
01953         /* The aircraft is now heading for a different hangar than the next in the orders */
01954         extern void AircraftNextAirportPos_and_Order(Aircraft *a);
01955         AircraftNextAirportPos_and_Order(a);
01956       }
01957     }
01958   }
01959 
01960   return CommandCost();
01961 
01962 }
01963 
01968 void Vehicle::UpdateVisualEffect(bool allow_power_change)
01969 {
01970   bool powered_before = HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
01971   const Engine *e = Engine::Get(this->engine_type);
01972 
01973   /* Evaluate properties */
01974   byte visual_effect;
01975   switch (e->type) {
01976     case VEH_TRAIN: visual_effect = e->u.rail.visual_effect; break;
01977     case VEH_ROAD:  visual_effect = e->u.road.visual_effect; break;
01978     case VEH_SHIP:  visual_effect = e->u.ship.visual_effect; break;
01979     default:        visual_effect = 1 << VE_DISABLE_EFFECT;  break;
01980   }
01981 
01982   /* Check powered wagon / visual effect callback */
01983   if (HasBit(e->info.callback_mask, CBM_VEHICLE_VISUAL_EFFECT)) {
01984     uint16 callback = GetVehicleCallback(CBID_VEHICLE_VISUAL_EFFECT, 0, 0, this->engine_type, this);
01985 
01986     if (callback != CALLBACK_FAILED) {
01987       callback = GB(callback, 0, 8);
01988       /* Avoid accidentally setting 'visual_effect' to the default value
01989        * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */
01990       if (callback == VE_DEFAULT) {
01991         assert(HasBit(callback, VE_DISABLE_EFFECT));
01992         SB(callback, VE_TYPE_START, VE_TYPE_COUNT, 0);
01993       }
01994       visual_effect = callback;
01995     }
01996   }
01997 
01998   /* Apply default values */
01999   if (visual_effect == VE_DEFAULT ||
02000       (!HasBit(visual_effect, VE_DISABLE_EFFECT) && GB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT) == VE_TYPE_DEFAULT)) {
02001     /* Only train engines have default effects.
02002      * Note: This is independent of whether the engine is a front engine or articulated part or whatever. */
02003     if (e->type != VEH_TRAIN || e->u.rail.railveh_type == RAILVEH_WAGON || !IsInsideMM(e->u.rail.engclass, EC_STEAM, EC_MONORAIL)) {
02004       if (visual_effect == VE_DEFAULT) {
02005         visual_effect = 1 << VE_DISABLE_EFFECT;
02006       } else {
02007         SetBit(visual_effect, VE_DISABLE_EFFECT);
02008       }
02009     } else {
02010       if (visual_effect == VE_DEFAULT) {
02011         /* Also set the offset */
02012         visual_effect = (VE_OFFSET_CENTRE - (e->u.rail.engclass == EC_STEAM ? 4 : 0)) << VE_OFFSET_START;
02013       }
02014       SB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT, e->u.rail.engclass - EC_STEAM + VE_TYPE_STEAM);
02015     }
02016   }
02017 
02018   this->vcache.cached_vis_effect = visual_effect;
02019 
02020   if (!allow_power_change && powered_before != HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
02021     ToggleBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER);
02022     ShowNewGrfVehicleError(this->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_POWERED_WAGON, GBUG_VEH_POWERED_WAGON, false);
02023   }
02024 }
02025 
02026 static const int8 _vehicle_smoke_pos[8] = {
02027   1, 1, 1, 0, -1, -1, -1, 0
02028 };
02029 
02034 void Vehicle::ShowVisualEffect() const
02035 {
02036   assert(this->IsPrimaryVehicle());
02037   bool sound = false;
02038 
02039   /* Do not show any smoke when:
02040    * - vehicle smoke is disabled by the player
02041    * - the vehicle is slowing down or stopped (by the player)
02042    * - the vehicle is moving very slowly
02043    */
02044   if (_settings_game.vehicle.smoke_amount == 0 ||
02045       this->vehstatus & (VS_TRAIN_SLOWING | VS_STOPPED) ||
02046       this->cur_speed < 2) {
02047     return;
02048   }
02049   if (this->type == VEH_TRAIN) {
02050     const Train *t = Train::From(this);
02051     /* For trains, do not show any smoke when:
02052      * - the train is reversing
02053      * - is entering a station with an order to stop there and its speed is equal to maximum station entering speed
02054      */
02055     if (HasBit(t->flags, VRF_REVERSING) ||
02056         (IsRailStationTile(t->tile) && t->IsFrontEngine() && t->current_order.ShouldStopAtStation(t, GetStationIndex(t->tile)) &&
02057         t->cur_speed >= t->Train::GetCurrentMaxSpeed())) {
02058       return;
02059     }
02060   }
02061 
02062   const Vehicle *v = this;
02063 
02064   do {
02065     int effect_offset = GB(v->vcache.cached_vis_effect, VE_OFFSET_START, VE_OFFSET_COUNT) - VE_OFFSET_CENTRE;
02066     byte effect_type = GB(v->vcache.cached_vis_effect, VE_TYPE_START, VE_TYPE_COUNT);
02067     bool disable_effect = HasBit(v->vcache.cached_vis_effect, VE_DISABLE_EFFECT);
02068 
02069     /* Show no smoke when:
02070      * - Smoke has been disabled for this vehicle
02071      * - The vehicle is not visible
02072      * - The vehicle is on a depot tile
02073      * - The vehicle is on a tunnel tile
02074      * - The vehicle is a train engine that is currently unpowered */
02075     if (disable_effect ||
02076         v->vehstatus & VS_HIDDEN ||
02077         IsDepotTile(v->tile) ||
02078         IsTunnelTile(v->tile) ||
02079         (v->type == VEH_TRAIN &&
02080         !HasPowerOnRail(Train::From(v)->railtype, GetTileRailType(v->tile)))) {
02081       continue;
02082     }
02083 
02084     int x = _vehicle_smoke_pos[v->direction] * effect_offset;
02085     int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
02086 
02087     if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) {
02088       x = -x;
02089       y = -y;
02090     }
02091 
02092     switch (effect_type) {
02093       case VE_TYPE_STEAM:
02094         /* Steam smoke - amount is gradually falling until vehicle reaches its maximum speed, after that it's normal.
02095          * Details: while vehicle's current speed is gradually increasing, steam plumes' density decreases by one third each
02096          * third of its maximum speed spectrum. Steam emission finally normalises at very close to vehicle's maximum speed.
02097          * REGULATION:
02098          * - instead of 1, 4 / 2^smoke_amount (max. 2) is used to provide sufficient regulation to steam puffs' amount. */
02099         if (GB(v->tick_counter, 0, ((4 >> _settings_game.vehicle.smoke_amount) + ((this->cur_speed * 3) / this->vcache.cached_max_speed))) == 0) {
02100           CreateEffectVehicleRel(v, x, y, 10, EV_STEAM_SMOKE);
02101           sound = true;
02102         }
02103         break;
02104 
02105       case VE_TYPE_DIESEL: {
02106         /* Diesel smoke - thicker when vehicle is starting, gradually subsiding till it reaches its maximum speed
02107          * when smoke emission stops.
02108          * Details: Vehicle's (max.) speed spectrum is divided into 32 parts. When max. speed is reached, chance for smoke
02109          * emission erodes by 32 (1/4). For trains, power and weight come in handy too to either increase smoke emission in
02110          * 6 steps (1000HP each) if the power is low or decrease smoke emission in 6 steps (512 tonnes each) if the train
02111          * isn't overweight. Power and weight contributions are expressed in a way that neither extreme power, nor
02112          * extreme weight can ruin the balance (e.g. FreightWagonMultiplier) in the formula. When the vehicle reaches
02113          * maximum speed no diesel_smoke is emitted.
02114          * REGULATION:
02115          * - up to which speed a diesel vehicle is emitting smoke (with reduced/small setting only until 1/2 of max_speed),
02116          * - in Chance16 - the last value is 512 / 2^smoke_amount (max. smoke when 128 = smoke_amount of 2). */
02117         int power_weight_effect = 0;
02118         if (v->type == VEH_TRAIN) {
02119           power_weight_effect = (32 >> (Train::From(this)->gcache.cached_power >> 10)) - (32 >> (Train::From(this)->gcache.cached_weight >> 9));
02120         }
02121         if (this->cur_speed < (this->vcache.cached_max_speed >> (2 >> _settings_game.vehicle.smoke_amount)) &&
02122             Chance16((64 - ((this->cur_speed << 5) / this->vcache.cached_max_speed) + power_weight_effect), (512 >> _settings_game.vehicle.smoke_amount))) {
02123           CreateEffectVehicleRel(v, x, y, 10, EV_DIESEL_SMOKE);
02124           sound = true;
02125         }
02126         break;
02127       }
02128 
02129       case VE_TYPE_ELECTRIC:
02130         /* Electric train's spark - more often occurs when train is departing (more load)
02131          * Details: Electric locomotives are usually at least twice as powerful as their diesel counterparts, so spark
02132          * emissions are kept simple. Only when starting, creating huge force are sparks more likely to happen, but when
02133          * reaching its max. speed, quarter by quarter of it, chance decreases untill the usuall 2,22% at train's top speed.
02134          * REGULATION:
02135          * - in Chance16 the last value is 360 / 2^smoke_amount (max. sparks when 90 = smoke_amount of 2). */
02136         if (GB(v->tick_counter, 0, 2) == 0 &&
02137             Chance16((6 - ((this->cur_speed << 2) / this->vcache.cached_max_speed)), (360 >> _settings_game.vehicle.smoke_amount))) {
02138           CreateEffectVehicleRel(v, x, y, 10, EV_ELECTRIC_SPARK);
02139           sound = true;
02140         }
02141         break;
02142 
02143       default:
02144         break;
02145     }
02146   } while ((v = v->Next()) != NULL);
02147 
02148   if (sound) PlayVehicleSound(this, VSE_VISUAL_EFFECT);
02149 }
02150 
02155 void Vehicle::SetNext(Vehicle *next)
02156 {
02157   assert(this != next);
02158 
02159   if (this->next != NULL) {
02160     /* We had an old next vehicle. Update the first and previous pointers */
02161     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
02162       v->first = this->next;
02163     }
02164     this->next->previous = NULL;
02165   }
02166 
02167   this->next = next;
02168 
02169   if (this->next != NULL) {
02170     /* A new next vehicle. Update the first and previous pointers */
02171     if (this->next->previous != NULL) this->next->previous->next = NULL;
02172     this->next->previous = this;
02173     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
02174       v->first = this->first;
02175     }
02176   }
02177 }
02178 
02184 void Vehicle::AddToShared(Vehicle *shared_chain)
02185 {
02186   assert(this->previous_shared == NULL && this->next_shared == NULL);
02187 
02188   if (!shared_chain->orders.list) {
02189     assert(shared_chain->previous_shared == NULL);
02190     assert(shared_chain->next_shared == NULL);
02191     this->orders.list = shared_chain->orders.list = new OrderList(NULL, shared_chain);
02192   }
02193 
02194   this->next_shared     = shared_chain->next_shared;
02195   this->previous_shared = shared_chain;
02196 
02197   shared_chain->next_shared = this;
02198 
02199   if (this->next_shared != NULL) this->next_shared->previous_shared = this;
02200 
02201   shared_chain->orders.list->AddVehicle(this);
02202 }
02203 
02207 void Vehicle::RemoveFromShared()
02208 {
02209   /* Remember if we were first and the old window number before RemoveVehicle()
02210    * as this changes first if needed. */
02211   bool were_first = (this->FirstShared() == this);
02212   VehicleListIdentifier vli(VL_SHARED_ORDERS, this->type, this->owner, this->FirstShared()->index);
02213 
02214   this->orders.list->RemoveVehicle(this);
02215 
02216   if (!were_first) {
02217     /* We are not the first shared one, so only relink our previous one. */
02218     this->previous_shared->next_shared = this->NextShared();
02219   }
02220 
02221   if (this->next_shared != NULL) this->next_shared->previous_shared = this->previous_shared;
02222 
02223 
02224   if (this->orders.list->GetNumVehicles() == 1) {
02225     /* When there is only one vehicle, remove the shared order list window. */
02226     DeleteWindowById(GetWindowClassForVehicleType(this->type), vli.Pack());
02227     InvalidateVehicleOrder(this->FirstShared(), 0);
02228   } else if (were_first) {
02229     /* If we were the first one, update to the new first one.
02230      * Note: FirstShared() is already the new first */
02231     InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.Pack(), this->FirstShared()->index | (1U << 31));
02232   }
02233 
02234   this->next_shared     = NULL;
02235   this->previous_shared = NULL;
02236 }
02237 
02243 Order *Vehicle::GetNextManualOrder(int index) const
02244 {
02245   Order *order = this->GetOrder(index);
02246   while(order != NULL && order->IsType(OT_AUTOMATIC)) {
02247     order = order->next;
02248   }
02249   return order;
02250 }
02251 
02252 void VehiclesYearlyLoop()
02253 {
02254   Vehicle *v;
02255   FOR_ALL_VEHICLES(v) {
02256     if (v->IsPrimaryVehicle()) {
02257       /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
02258       Money profit = v->GetDisplayProfitThisYear();
02259       if (v->age >= 730 && profit < 0) {
02260         if (_settings_client.gui.vehicle_income_warn && v->owner == _local_company) {
02261           SetDParam(0, v->index);
02262           SetDParam(1, profit);
02263           AddVehicleNewsItem(
02264             STR_NEWS_VEHICLE_IS_UNPROFITABLE,
02265             NS_ADVICE,
02266             v->index
02267           );
02268         }
02269         AI::NewEvent(v->owner, new AIEventVehicleUnprofitable(v->index));
02270       }
02271 
02272       v->profit_last_year = v->profit_this_year;
02273       v->profit_this_year = 0;
02274       SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
02275     }
02276   }
02277 }
02278 
02279 
02289 bool CanVehicleUseStation(EngineID engine_type, const Station *st)
02290 {
02291   const Engine *e = Engine::GetIfValid(engine_type);
02292   assert(e != NULL);
02293 
02294   switch (e->type) {
02295     case VEH_TRAIN:
02296       return (st->facilities & FACIL_TRAIN) != 0;
02297 
02298     case VEH_ROAD:
02299       /* For road vehicles we need the vehicle to know whether it can actually
02300        * use the station, but if it doesn't have facilities for RVs it is
02301        * certainly not possible that the station can be used. */
02302       return (st->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP)) != 0;
02303 
02304     case VEH_SHIP:
02305       return (st->facilities & FACIL_DOCK) != 0;
02306 
02307     case VEH_AIRCRAFT:
02308       return (st->facilities & FACIL_AIRPORT) != 0 &&
02309           (st->airport.GetFTA()->flags & (e->u.air.subtype & AIR_CTOL ? AirportFTAClass::AIRPLANES : AirportFTAClass::HELICOPTERS)) != 0;
02310 
02311     default:
02312       return false;
02313   }
02314 }
02315 
02322 bool CanVehicleUseStation(const Vehicle *v, const Station *st)
02323 {
02324   if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != NULL;
02325 
02326   return CanVehicleUseStation(v->engine_type, st);
02327 }
02328 
02334 GroundVehicleCache *Vehicle::GetGroundVehicleCache()
02335 {
02336   assert(this->IsGroundVehicle());
02337   if (this->type == VEH_TRAIN) {
02338     return &Train::From(this)->gcache;
02339   } else {
02340     return &RoadVehicle::From(this)->gcache;
02341   }
02342 }
02343 
02349 const GroundVehicleCache *Vehicle::GetGroundVehicleCache() const
02350 {
02351   assert(this->IsGroundVehicle());
02352   if (this->type == VEH_TRAIN) {
02353     return &Train::From(this)->gcache;
02354   } else {
02355     return &RoadVehicle::From(this)->gcache;
02356   }
02357 }
02358 
02367 void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8 num_vehicles)
02368 {
02369   if (v->type == VEH_TRAIN) {
02370     Train *u = Train::From(v);
02371     /* If the first vehicle in the selection is part of an articulated vehicle, add the previous parts of the vehicle. */
02372     if (u->IsArticulatedPart()) {
02373       u = u->GetFirstEnginePart();
02374       while (u->index != v->index) {
02375         set.Include(u->index);
02376         u = u->GetNextArticulatedPart();
02377       }
02378     }
02379 
02380     for (;u != NULL && num_vehicles > 0; num_vehicles--, u = u->Next()) {
02381       /* Include current vehicle in the selection. */
02382       set.Include(u->index);
02383 
02384       /* If the vehicle is multiheaded, add the other part too. */
02385       if (u->IsMultiheaded()) set.Include(u->other_multiheaded_part->index);
02386     }
02387 
02388     /* If the last vehicle is part of an articulated vehicle, add the following parts of the vehicle. */
02389     while (u != NULL && u->IsArticulatedPart()) {
02390       set.Include(u->index);
02391       u = u->Next();
02392     }
02393   }
02394 }

Generated on Thu Jan 20 22:57:43 2011 for OpenTTD by  doxygen 1.6.1