vehicle.cpp

Go to the documentation of this file.
00001 /* $Id: vehicle.cpp 14385 2008-09-22 19:57:31Z rubidium $ */
00002 
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "road_map.h"
00008 #include "roadveh.h"
00009 #include "ship.h"
00010 #include "spritecache.h"
00011 #include "tile_cmd.h"
00012 #include "landscape.h"
00013 #include "timetable.h"
00014 #include "viewport_func.h"
00015 #include "gfx_func.h"
00016 #include "news.h"
00017 #include "command_func.h"
00018 #include "saveload.h"
00019 #include "player_func.h"
00020 #include "engine.h"
00021 #include "debug.h"
00022 #include "vehicle_gui.h"
00023 #include "depot.h"
00024 #include "station.h"
00025 #include "rail_type.h"
00026 #include "train.h"
00027 #include "aircraft.h"
00028 #include "industry_map.h"
00029 #include "station_map.h"
00030 #include "water_map.h"
00031 #include "network/network.h"
00032 #include "yapf/yapf.h"
00033 #include "newgrf_callbacks.h"
00034 #include "newgrf_engine.h"
00035 #include "newgrf_sound.h"
00036 #include "group.h"
00037 #include "order.h"
00038 #include "strings_func.h"
00039 #include "zoom_func.h"
00040 #include "functions.h"
00041 #include "date_func.h"
00042 #include "window_func.h"
00043 #include "vehicle_func.h"
00044 #include "signal_func.h"
00045 #include "sound_func.h"
00046 #include "variables.h"
00047 #include "autoreplace_func.h"
00048 #include "autoreplace_gui.h"
00049 #include "string_func.h"
00050 #include "settings_type.h"
00051 
00052 #include "table/sprites.h"
00053 #include "table/strings.h"
00054 
00055 #define INVALID_COORD (0x7fffffff)
00056 #define GEN_HASH(x, y) ((GB((y), 6, 6) << 6) + GB((x), 7, 6))
00057 
00058 VehicleID _vehicle_id_ctr_day;
00059 Vehicle *_place_clicked_vehicle;
00060 VehicleID _new_vehicle_id;
00061 uint16 _returned_refit_capacity;
00062 
00063 
00064 /* Tables used in vehicle.h to find the right command for a certain vehicle type */
00065 const uint32 _veh_build_proc_table[] = {
00066   CMD_BUILD_RAIL_VEHICLE,
00067   CMD_BUILD_ROAD_VEH,
00068   CMD_BUILD_SHIP,
00069   CMD_BUILD_AIRCRAFT,
00070 };
00071 const uint32 _veh_sell_proc_table[] = {
00072   CMD_SELL_RAIL_WAGON,
00073   CMD_SELL_ROAD_VEH,
00074   CMD_SELL_SHIP,
00075   CMD_SELL_AIRCRAFT,
00076 };
00077 
00078 const uint32 _veh_refit_proc_table[] = {
00079   CMD_REFIT_RAIL_VEHICLE,
00080   CMD_REFIT_ROAD_VEH,
00081   CMD_REFIT_SHIP,
00082   CMD_REFIT_AIRCRAFT,
00083 };
00084 
00085 const uint32 _send_to_depot_proc_table[] = {
00086   CMD_SEND_TRAIN_TO_DEPOT,
00087   CMD_SEND_ROADVEH_TO_DEPOT,
00088   CMD_SEND_SHIP_TO_DEPOT,
00089   CMD_SEND_AIRCRAFT_TO_HANGAR,
00090 };
00091 
00092 
00093 /* Initialize the vehicle-pool */
00094 DEFINE_OLD_POOL_GENERIC(Vehicle, Vehicle)
00095 
00096 
00100 bool Vehicle::NeedsAutorenewing(const Player *p) const
00101 {
00102   /* We can always generate the Player pointer when we have the vehicle.
00103    * However this takes time and since the Player pointer is often present
00104    * when this function is called then it's faster to pass the pointer as an
00105    * argument rather than finding it again. */
00106   assert(p == GetPlayer(this->owner));
00107 
00108   if (!p->engine_renew) return false;
00109   if (this->age - this->max_age < (p->engine_renew_months * 30)) return false;
00110 
00111   return true;
00112 }
00113 
00114 void VehicleServiceInDepot(Vehicle *v)
00115 {
00116   v->date_of_last_service = _date;
00117   v->breakdowns_since_last_service = 0;
00118   v->reliability = GetEngine(v->engine_type)->reliability;
00119   InvalidateWindow(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
00120 }
00121 
00122 bool Vehicle::NeedsServicing() const
00123 {
00124   if (this->vehstatus & (VS_STOPPED | VS_CRASHED)) return false;
00125 
00126   if (_patches.no_servicing_if_no_breakdowns && _opt.diff.vehicle_breakdowns == 0) {
00127     /* Vehicles set for autoreplacing needs to go to a depot even if breakdowns are turned off.
00128      * Note: If servicing is enabled, we postpone replacement till next service. */
00129     return EngineHasReplacementForPlayer(GetPlayer(this->owner), this->engine_type, this->group_id);
00130   }
00131 
00132   return _patches.servint_ispercent ?
00133     (this->reliability < GetEngine(this->engine_type)->reliability * (100 - this->service_interval) / 100) :
00134     (this->date_of_last_service + this->service_interval < _date);
00135 }
00136 
00137 bool Vehicle::NeedsAutomaticServicing() const
00138 {
00139   if (_patches.gotodepot && VehicleHasDepotOrders(this)) return false;
00140   if (this->current_order.type == OT_LOADING)            return false;
00141   if (this->current_order.type == OT_GOTO_DEPOT && this->current_order.flags & OFB_HALT_IN_DEPOT) return false;
00142   return NeedsServicing();
00143 }
00144 
00145 StringID VehicleInTheWayErrMsg(const Vehicle* v)
00146 {
00147   switch (v->type) {
00148     case VEH_TRAIN:    return STR_8803_TRAIN_IN_THE_WAY;
00149     case VEH_ROAD:     return STR_9000_ROAD_VEHICLE_IN_THE_WAY;
00150     case VEH_AIRCRAFT: return STR_A015_AIRCRAFT_IN_THE_WAY;
00151     default:           return STR_980E_SHIP_IN_THE_WAY;
00152   }
00153 }
00154 
00155 static void *EnsureNoVehicleProcZ(Vehicle *v, void *data)
00156 {
00157   byte z = *(byte*)data;
00158 
00159   if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL;
00160   if (v->z_pos > z) return NULL;
00161 
00162   _error_message = VehicleInTheWayErrMsg(v);
00163   return v;
00164 }
00165 
00166 bool EnsureNoVehicleOnGround(TileIndex tile)
00167 {
00168   byte z = GetTileMaxZ(tile);
00169   return !HasVehicleOnPos(tile, &z, &EnsureNoVehicleProcZ);
00170 }
00171 
00173 static void *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
00174 {
00175   if (v->type != VEH_TRAIN && v->type != VEH_ROAD) return NULL;
00176 
00177   _error_message = VehicleInTheWayErrMsg(v);
00178   return v;
00179 }
00180 
00187 bool HasVehicleOnTunnelBridge(TileIndex tile, TileIndex endtile)
00188 {
00189   return HasVehicleOnPos(tile, NULL, &GetVehicleTunnelBridgeProc) ||
00190       HasVehicleOnPos(endtile, NULL, &GetVehicleTunnelBridgeProc);
00191 }
00192 
00193 
00194 static void UpdateVehiclePosHash(Vehicle* v, int x, int y);
00195 
00196 void VehiclePositionChanged(Vehicle *v)
00197 {
00198   int img = v->cur_image;
00199   Point pt = RemapCoords(v->x_pos + v->x_offs, v->y_pos + v->y_offs, v->z_pos);
00200   const Sprite* spr = GetSprite(img);
00201 
00202   pt.x += spr->x_offs;
00203   pt.y += spr->y_offs;
00204 
00205   UpdateVehiclePosHash(v, pt.x, pt.y);
00206 
00207   v->left_coord = pt.x;
00208   v->top_coord = pt.y;
00209   v->right_coord = pt.x + spr->width + 2;
00210   v->bottom_coord = pt.y + spr->height + 2;
00211 }
00212 
00214 void AfterLoadVehicles(bool clear_te_id)
00215 {
00216   Vehicle *v;
00217 
00218   FOR_ALL_VEHICLES(v) {
00219     /* Reinstate the previous pointer */
00220     if (v->Next() != NULL) v->Next()->previous = v;
00221 
00222     v->UpdateDeltaXY(v->direction);
00223 
00224     if (clear_te_id) v->fill_percent_te_id = INVALID_TE_ID;
00225     v->first = NULL;
00226     if (v->type == VEH_TRAIN) v->u.rail.first_engine = INVALID_ENGINE;
00227     if (v->type == VEH_ROAD)  v->u.road.first_engine = INVALID_ENGINE;
00228 
00229     v->cargo.InvalidateCache();
00230   }
00231 
00232   FOR_ALL_VEHICLES(v) {
00233     /* Fill the first pointers */
00234     if (v->Previous() == NULL) {
00235       for (Vehicle *u = v; u != NULL; u = u->Next()) {
00236         u->first = v;
00237       }
00238     }
00239   }
00240 
00241   FOR_ALL_VEHICLES(v) {
00242     assert(v->first != NULL);
00243 
00244     if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) {
00245       if (IsFrontEngine(v)) v->u.rail.last_speed = v->cur_speed; // update displayed train speed
00246       TrainConsistChanged(v, false);
00247     } else if (v->type == VEH_ROAD && IsRoadVehFront(v)) {
00248       RoadVehUpdateCache(v);
00249     }
00250   }
00251 
00252   FOR_ALL_VEHICLES(v) {
00253     switch (v->type) {
00254       case VEH_ROAD:
00255         v->u.road.roadtype = HasBit(EngInfo(v->engine_type)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD;
00256         v->u.road.compatible_roadtypes = RoadTypeToRoadTypes(v->u.road.roadtype);
00257         /* FALL THROUGH */
00258       case VEH_TRAIN:
00259       case VEH_SHIP:
00260         v->cur_image = v->GetImage(v->direction);
00261         break;
00262 
00263       case VEH_AIRCRAFT:
00264         if (IsNormalAircraft(v)) {
00265           v->cur_image = v->GetImage(v->direction);
00266 
00267           /* The plane's shadow will have the same image as the plane */
00268           Vehicle *shadow = v->Next();
00269           shadow->cur_image = v->cur_image;
00270 
00271           /* In the case of a helicopter we will update the rotor sprites */
00272           if (v->subtype == AIR_HELICOPTER) {
00273             Vehicle *rotor = shadow->Next();
00274             rotor->cur_image = GetRotorImage(v);
00275           }
00276 
00277           UpdateAircraftCache(v);
00278         }
00279         break;
00280       default: break;
00281     }
00282 
00283     v->left_coord = INVALID_COORD;
00284     VehiclePositionChanged(v);
00285   }
00286 }
00287 
00288 Vehicle::Vehicle()
00289 {
00290   this->type               = VEH_INVALID;
00291   this->left_coord         = INVALID_COORD;
00292   this->group_id           = DEFAULT_GROUP;
00293   this->fill_percent_te_id = INVALID_TE_ID;
00294   this->first              = this;
00295   this->colormap           = PAL_NONE;
00296 }
00297 
00302 byte VehicleRandomBits()
00303 {
00304   return GB(Random(), 0, 8);
00305 }
00306 
00307 
00308 /* static */ bool Vehicle::AllocateList(Vehicle **vl, int num)
00309 {
00310   uint counter = _Vehicle_pool.first_free_index;
00311 
00312   for (int i = 0; i != num; i++) {
00313     Vehicle *v = AllocateRaw(counter);
00314 
00315     if (v == NULL) return false;
00316     v = new (v) InvalidVehicle();
00317 
00318     if (vl != NULL) {
00319       vl[i] = v;
00320     }
00321     counter++;
00322   }
00323 
00324   return true;
00325 }
00326 
00327 /* Size of the hash, 6 = 64 x 64, 7 = 128 x 128. Larger sizes will (in theory) reduce hash
00328  * lookup times at the expense of memory usage. */
00329 const int HASH_BITS = 7;
00330 const int HASH_SIZE = 1 << HASH_BITS;
00331 const int HASH_MASK = HASH_SIZE - 1;
00332 const int TOTAL_HASH_SIZE = 1 << (HASH_BITS * 2);
00333 const int TOTAL_HASH_MASK = TOTAL_HASH_SIZE - 1;
00334 
00335 /* Resolution of the hash, 0 = 1*1 tile, 1 = 2*2 tiles, 2 = 4*4 tiles, etc.
00336  * Profiling results show that 0 is fastest. */
00337 const int HASH_RES = 0;
00338 
00339 static Vehicle *_new_vehicle_position_hash[TOTAL_HASH_SIZE];
00340 
00341 static void *VehicleFromHash(int xl, int yl, int xu, int yu, void *data, VehicleFromPosProc *proc, bool find_first)
00342 {
00343   for (int y = yl; ; y = (y + (1 << HASH_BITS)) & (HASH_MASK << HASH_BITS)) {
00344     for (int x = xl; ; x = (x + 1) & HASH_MASK) {
00345       Vehicle *v = _new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
00346       for (; v != NULL; v = v->next_new_hash) {
00347         void *a = proc(v, data);
00348         if (find_first && a != NULL) return a;
00349       }
00350       if (x == xu) break;
00351     }
00352     if (y == yu) break;
00353   }
00354 
00355   return NULL;
00356 }
00357 
00358 
00370 static void *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc, bool find_first)
00371 {
00372   const int COLL_DIST = 6;
00373 
00374   /* Hash area to scan is from xl,yl to xu,yu */
00375   int xl = GB((x - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
00376   int xu = GB((x + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS);
00377   int yl = GB((y - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
00378   int yu = GB((y + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS;
00379 
00380   return VehicleFromHash(xl, yl, xu, yu, data, proc, find_first);
00381 }
00382 
00397 void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
00398 {
00399   VehicleFromPosXY(x, y, data, proc, false);
00400 }
00401 
00413 bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
00414 {
00415   return VehicleFromPosXY(x, y, data, proc, true) != NULL;
00416 }
00417 
00428 static void *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc, bool find_first)
00429 {
00430   int x = GB(TileX(tile), HASH_RES, HASH_BITS);
00431   int y = GB(TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS;
00432 
00433   Vehicle *v = _new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
00434   for (; v != NULL; v = v->next_new_hash) {
00435     if (v->tile != tile) continue;
00436 
00437     void *a = proc(v, data);
00438     if (find_first && a != NULL) return a;
00439   }
00440 
00441   return NULL;
00442 }
00443 
00457 void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
00458 {
00459   VehicleFromPos(tile, data, proc, false);
00460 }
00461 
00472 bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
00473 {
00474   return VehicleFromPos(tile, data, proc, true) != NULL;
00475 }
00476 
00477 
00478 static void UpdateNewVehiclePosHash(Vehicle *v, bool remove)
00479 {
00480   Vehicle **old_hash = v->old_new_hash;
00481   Vehicle **new_hash;
00482 
00483   if (remove) {
00484     new_hash = NULL;
00485   } else {
00486     int x = GB(TileX(v->tile), HASH_RES, HASH_BITS);
00487     int y = GB(TileY(v->tile), HASH_RES, HASH_BITS) << HASH_BITS;
00488     new_hash = &_new_vehicle_position_hash[(x + y) & TOTAL_HASH_MASK];
00489   }
00490 
00491   if (old_hash == new_hash) return;
00492 
00493   /* Remove from the old position in the hash table */
00494   if (old_hash != NULL) {
00495     Vehicle *last = NULL;
00496     Vehicle *u = *old_hash;
00497     while (u != v) {
00498       last = u;
00499       u = u->next_new_hash;
00500       assert(u != NULL);
00501     }
00502 
00503     if (last == NULL) {
00504       *old_hash = v->next_new_hash;
00505     } else {
00506       last->next_new_hash = v->next_new_hash;
00507     }
00508   }
00509 
00510   /* Insert vehicle at beginning of the new position in the hash table */
00511   if (new_hash != NULL) {
00512     v->next_new_hash = *new_hash;
00513     *new_hash = v;
00514     assert(v != v->next_new_hash);
00515   }
00516 
00517   /* Remember current hash position */
00518   v->old_new_hash = new_hash;
00519 }
00520 
00521 static Vehicle *_vehicle_position_hash[0x1000];
00522 
00523 static void UpdateVehiclePosHash(Vehicle* v, int x, int y)
00524 {
00525   UpdateNewVehiclePosHash(v, x == INVALID_COORD);
00526 
00527   Vehicle **old_hash, **new_hash;
00528   int old_x = v->left_coord;
00529   int old_y = v->top_coord;
00530 
00531   new_hash = (x == INVALID_COORD) ? NULL : &_vehicle_position_hash[GEN_HASH(x, y)];
00532   old_hash = (old_x == INVALID_COORD) ? NULL : &_vehicle_position_hash[GEN_HASH(old_x, old_y)];
00533 
00534   if (old_hash == new_hash) return;
00535 
00536   /* remove from hash table? */
00537   if (old_hash != NULL) {
00538     Vehicle *last = NULL;
00539     Vehicle *u = *old_hash;
00540     while (u != v) {
00541       last = u;
00542       u = u->next_hash;
00543       assert(u != NULL);
00544     }
00545 
00546     if (last == NULL) {
00547       *old_hash = v->next_hash;
00548     } else {
00549       last->next_hash = v->next_hash;
00550     }
00551   }
00552 
00553   /* insert into hash table? */
00554   if (new_hash != NULL) {
00555     v->next_hash = *new_hash;
00556     *new_hash = v;
00557   }
00558 }
00559 
00560 void ResetVehiclePosHash()
00561 {
00562   Vehicle *v;
00563   FOR_ALL_VEHICLES(v) { v->old_new_hash = NULL; }
00564   memset(_vehicle_position_hash, 0, sizeof(_vehicle_position_hash));
00565   memset(_new_vehicle_position_hash, 0, sizeof(_new_vehicle_position_hash));
00566 }
00567 
00568 void ResetVehicleColorMap()
00569 {
00570   Vehicle *v;
00571   FOR_ALL_VEHICLES(v) { v->colormap = PAL_NONE; }
00572 }
00573 
00574 void InitializeVehicles()
00575 {
00576   _Vehicle_pool.CleanPool();
00577   _Vehicle_pool.AddBlockToPool();
00578 
00579   ResetVehiclePosHash();
00580 }
00581 
00582 Vehicle *GetLastVehicleInChain(Vehicle *v)
00583 {
00584   while (v->Next() != NULL) v = v->Next();
00585   return v;
00586 }
00587 
00588 uint CountVehiclesInChain(const Vehicle* v)
00589 {
00590   uint count = 0;
00591   do count++; while ((v = v->Next()) != NULL);
00592   return count;
00593 }
00594 
00599 bool IsEngineCountable(const Vehicle *v)
00600 {
00601   switch (v->type) {
00602     case VEH_AIRCRAFT: return IsNormalAircraft(v); // don't count plane shadows and helicopter rotors
00603     case VEH_TRAIN:
00604       return !IsArticulatedPart(v) && // tenders and other articulated parts
00605       !IsRearDualheaded(v); // rear parts of multiheaded engines
00606     case VEH_ROAD: return IsRoadVehFront(v);
00607     case VEH_SHIP: return true;
00608     default: return false; // Only count player buildable vehicles
00609   }
00610 }
00611 
00612 void Vehicle::PreDestructor()
00613 {
00614   if (CleaningPool()) return;
00615 
00616   if (IsValidStationID(this->last_station_visited)) {
00617     GetStation(this->last_station_visited)->loading_vehicles.remove(this);
00618 
00619     HideFillingPercent(&this->fill_percent_te_id);
00620   }
00621 
00622   if (IsEngineCountable(this)) {
00623     GetPlayer(this->owner)->num_engines[this->engine_type]--;
00624     if (this->owner == _local_player) InvalidateAutoreplaceWindow(this->engine_type, this->group_id);
00625 
00626     if (IsValidGroupID(this->group_id)) GetGroup(this->group_id)->num_engines[this->engine_type]--;
00627     if (this->IsPrimaryVehicle()) DecreaseGroupNumVehicle(this->group_id);
00628   }
00629 
00630   if (this->type == VEH_ROAD) ClearSlot(this);
00631   if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) {
00632     Station *st = GetTargetAirportIfValid(this);
00633     if (st != NULL) {
00634       const AirportFTA *layout = st->Airport()->layout;
00635       CLRBITS(st->airport_flags, layout[this->u.air.previous_pos].block | layout[this->u.air.pos].block);
00636     }
00637   }
00638 
00639   if (this->type != VEH_TRAIN || (this->type == VEH_TRAIN && (IsFrontEngine(this) || IsFreeWagon(this)))) {
00640     InvalidateWindowData(WC_VEHICLE_DEPOT, this->tile);
00641   }
00642 
00643   this->cargo.Truncate(0);
00644   DeleteVehicleOrders(this);
00645 
00646   /* Now remove any artic part. This will trigger an other
00647    *  destroy vehicle, which on his turn can remove any
00648    *  other artic parts. */
00649   if ((this->type == VEH_TRAIN && EngineHasArticPart(this)) || (this->type == VEH_ROAD && RoadVehHasArticPart(this))) {
00650     delete this->Next();
00651   }
00652 
00653   Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
00654   if (w != NULL && WP(w, vp_d).follow_vehicle == this->index) {
00655     ScrollMainWindowTo(this->x_pos, this->y_pos, true); // lock the main view on the vehicle's last position
00656     WP(w, vp_d).follow_vehicle = INVALID_VEHICLE;
00657   }
00658 }
00659 
00660 Vehicle::~Vehicle()
00661 {
00662   free(this->name);
00663 
00664   if (CleaningPool()) return;
00665 
00666   this->SetNext(NULL);
00667   UpdateVehiclePosHash(this, INVALID_COORD, 0);
00668   this->next_hash = NULL;
00669   this->next_new_hash = NULL;
00670 
00671   DeleteVehicleNews(this->index, INVALID_STRING_ID);
00672 
00673   new (this) InvalidVehicle();
00674 }
00675 
00680 void DeleteVehicleChain(Vehicle *v)
00681 {
00682   assert(v->First() == v);
00683 
00684   do {
00685     Vehicle *u = v;
00686     /* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles,
00687      * it may happen that vehicle chain is deleted when visible */
00688     if (!(v->vehstatus & VS_HIDDEN)) MarkSingleVehicleDirty(v);
00689     v = v->Next();
00690     delete u;
00691   } while (v != NULL);
00692 }
00693 
00695 static Vehicle* _first_veh_in_depot_list;
00696 
00700 void VehicleEnteredDepotThisTick(Vehicle *v)
00701 {
00702   /* We need to set v->leave_depot_instantly as we have no control of it's contents at this time.
00703    * Vehicle should stop in the depot if it was in 'stopping' state - train intered depot while slowing down. */
00704   if ((HasBit(v->current_order.flags, OF_HALT_IN_DEPOT) && !HasBit(v->current_order.flags, OF_PART_OF_ORDERS) && v->current_order.type == OT_GOTO_DEPOT) ||
00705       (v->vehstatus & VS_STOPPED)) {
00706     /* we keep the vehicle in the depot since the user ordered it to stay */
00707     v->leave_depot_instantly = false;
00708   } else {
00709     /* the vehicle do not plan on stopping in the depot, so we stop it to ensure that it will not reserve the path
00710      * out of the depot before we might autoreplace it to a different engine. The new engine would not own the reserved path
00711      * we store that we stopped the vehicle, so autoreplace can start it again */
00712     v->vehstatus |= VS_STOPPED;
00713     v->leave_depot_instantly = true;
00714   }
00715 
00716   if (_first_veh_in_depot_list == NULL) {
00717     _first_veh_in_depot_list = v;
00718   } else {
00719     Vehicle *w = _first_veh_in_depot_list;
00720     while (w->depot_list != NULL) w = w->depot_list;
00721     w->depot_list = v;
00722   }
00723 }
00724 
00725 void CallVehicleTicks()
00726 {
00727   _first_veh_in_depot_list = NULL; // now we are sure it's initialized at the start of each tick
00728 
00729   Station *st;
00730   FOR_ALL_STATIONS(st) LoadUnloadStation(st);
00731 
00732   Vehicle *v;
00733   FOR_ALL_VEHICLES(v) {
00734     v->Tick();
00735 
00736     switch (v->type) {
00737       default: break;
00738 
00739       case VEH_TRAIN:
00740       case VEH_ROAD:
00741       case VEH_AIRCRAFT:
00742       case VEH_SHIP:
00743         if (v->type == VEH_TRAIN && IsTrainWagon(v)) continue;
00744         if (v->type == VEH_AIRCRAFT && v->subtype != AIR_HELICOPTER) continue;
00745         if (v->type == VEH_ROAD && !IsRoadVehFront(v)) continue;
00746 
00747         v->motion_counter += (v->direction & 1) ? (v->cur_speed * 3) / 4 : v->cur_speed;
00748         /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
00749         if (GB(v->motion_counter, 0, 8) < v->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
00750 
00751         /* Play an alterate running sound every 16 ticks */
00752         if (GB(v->tick_counter, 0, 4) == 0) PlayVehicleSound(v, v->cur_speed > 0 ? VSE_RUNNING_16 : VSE_STOPPED_16);
00753     }
00754   }
00755 
00756   /* now we handle all the vehicles that entered a depot this tick */
00757   v = _first_veh_in_depot_list;
00758   while (v != NULL) {
00759     Vehicle *w = v->depot_list;
00760     v->depot_list = NULL; // it should always be NULL at the end of each tick
00761     MaybeReplaceVehicle(v, false, true);
00762     v = w;
00763   }
00764 }
00765 
00771 bool CanRefitTo(EngineID engine_type, CargoID cid_to)
00772 {
00773   return HasBit(EngInfo(engine_type)->refit_mask, cid_to);
00774 }
00775 
00780 CargoID FindFirstRefittableCargo(EngineID engine_type)
00781 {
00782   uint32 refit_mask = EngInfo(engine_type)->refit_mask;
00783 
00784   if (refit_mask != 0) {
00785     for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
00786       if (HasBit(refit_mask, cid)) return cid;
00787     }
00788   }
00789 
00790   return CT_INVALID;
00791 }
00792 
00797 CommandCost GetRefitCost(EngineID engine_type)
00798 {
00799   Money base_cost;
00800   ExpensesType expense_type;
00801   switch (GetEngine(engine_type)->type) {
00802     case VEH_SHIP:
00803       base_cost = _price.ship_base;
00804       expense_type = EXPENSES_SHIP_RUN;
00805       break;
00806 
00807     case VEH_ROAD:
00808       base_cost = _price.roadveh_base;
00809       expense_type = EXPENSES_ROADVEH_RUN;
00810       break;
00811 
00812     case VEH_AIRCRAFT:
00813       base_cost = _price.aircraft_base;
00814       expense_type = EXPENSES_AIRCRAFT_RUN;
00815       break;
00816 
00817     case VEH_TRAIN:
00818       base_cost = 2 * ((RailVehInfo(engine_type)->railveh_type == RAILVEH_WAGON) ?
00819                _price.build_railwagon : _price.build_railvehicle);
00820       expense_type = EXPENSES_TRAIN_RUN;
00821       break;
00822 
00823     default: NOT_REACHED();
00824   }
00825   return CommandCost(expense_type, (EngInfo(engine_type)->refit_cost * base_cost) >> 10);
00826 }
00827 
00828 static void DoDrawVehicle(const Vehicle *v)
00829 {
00830   SpriteID image = v->cur_image;
00831   SpriteID pal;
00832 
00833   if (v->vehstatus & VS_DEFPAL) {
00834     pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
00835   } else {
00836     pal = PAL_NONE;
00837   }
00838 
00839   AddSortableSpriteToDraw(image, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
00840     v->sprite_width, v->sprite_height, v->z_height, v->z_pos, (v->vehstatus & VS_SHADOW) != 0);
00841 }
00842 
00843 void ViewportAddVehicles(DrawPixelInfo *dpi)
00844 {
00845   /* The bounding rectangle */
00846   const int l = dpi->left;
00847   const int r = dpi->left + dpi->width;
00848   const int t = dpi->top;
00849   const int b = dpi->top + dpi->height;
00850 
00851   /* The hash area to scan */
00852   int xl, xu, yl, yu;
00853 
00854   if (dpi->width + 70 < (1 << (7 + 6))) {
00855     xl = GB(l - 70, 7, 6);
00856     xu = GB(r,      7, 6);
00857   } else {
00858     /* scan whole hash row */
00859     xl = 0;
00860     xu = 0x3F;
00861   }
00862 
00863   if (dpi->height + 70 < (1 << (6 + 6))) {
00864     yl = GB(t - 70, 6, 6) << 6;
00865     yu = GB(b,      6, 6) << 6;
00866   } else {
00867     /* scan whole column */
00868     yl = 0;
00869     yu = 0x3F << 6;
00870   }
00871 
00872   for (int y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) {
00873     for (int x = xl;; x = (x + 1) & 0x3F) {
00874       const Vehicle *v = _vehicle_position_hash[x + y]; // already masked & 0xFFF
00875 
00876       while (v != NULL) {
00877         if (!(v->vehstatus & VS_HIDDEN) &&
00878             l <= v->right_coord &&
00879             t <= v->bottom_coord &&
00880             r >= v->left_coord &&
00881             b >= v->top_coord) {
00882           DoDrawVehicle(v);
00883         }
00884         v = v->next_hash;
00885       }
00886 
00887       if (x == xu) break;
00888     }
00889 
00890     if (y == yu) break;
00891   }
00892 }
00893 
00894 static void ChimneySmokeInit(Vehicle *v)
00895 {
00896   uint32 r = Random();
00897   v->cur_image = SPR_CHIMNEY_SMOKE_0 + GB(r, 0, 3);
00898   v->progress = GB(r, 16, 3);
00899 }
00900 
00901 static void ChimneySmokeTick(Vehicle *v)
00902 {
00903   if (v->progress > 0) {
00904     v->progress--;
00905   } else {
00906     TileIndex tile;
00907 
00908     BeginVehicleMove(v);
00909 
00910     tile = TileVirtXY(v->x_pos, v->y_pos);
00911     if (!IsTileType(tile, MP_INDUSTRY)) {
00912       EndVehicleMove(v);
00913       delete v;
00914       return;
00915     }
00916 
00917     if (v->cur_image != SPR_CHIMNEY_SMOKE_7) {
00918       v->cur_image++;
00919     } else {
00920       v->cur_image = SPR_CHIMNEY_SMOKE_0;
00921     }
00922     v->progress = 7;
00923     VehiclePositionChanged(v);
00924     EndVehicleMove(v);
00925   }
00926 }
00927 
00928 static void SteamSmokeInit(Vehicle *v)
00929 {
00930   v->cur_image = SPR_STEAM_SMOKE_0;
00931   v->progress = 12;
00932 }
00933 
00934 static void SteamSmokeTick(Vehicle *v)
00935 {
00936   bool moved = false;
00937 
00938   BeginVehicleMove(v);
00939 
00940   v->progress++;
00941 
00942   if ((v->progress & 7) == 0) {
00943     v->z_pos++;
00944     moved = true;
00945   }
00946 
00947   if ((v->progress & 0xF) == 4) {
00948     if (v->cur_image != SPR_STEAM_SMOKE_4) {
00949       v->cur_image++;
00950     } else {
00951       EndVehicleMove(v);
00952       delete v;
00953       return;
00954     }
00955     moved = true;
00956   }
00957 
00958   if (moved) {
00959     VehiclePositionChanged(v);
00960     EndVehicleMove(v);
00961   }
00962 }
00963 
00964 static void DieselSmokeInit(Vehicle *v)
00965 {
00966   v->cur_image = SPR_DIESEL_SMOKE_0;
00967   v->progress = 0;
00968 }
00969 
00970 static void DieselSmokeTick(Vehicle *v)
00971 {
00972   v->progress++;
00973 
00974   if ((v->progress & 3) == 0) {
00975     BeginVehicleMove(v);
00976     v->z_pos++;
00977     VehiclePositionChanged(v);
00978     EndVehicleMove(v);
00979   } else if ((v->progress & 7) == 1) {
00980     BeginVehicleMove(v);
00981     if (v->cur_image != SPR_DIESEL_SMOKE_5) {
00982       v->cur_image++;
00983       VehiclePositionChanged(v);
00984       EndVehicleMove(v);
00985     } else {
00986       EndVehicleMove(v);
00987       delete v;
00988     }
00989   }
00990 }
00991 
00992 static void ElectricSparkInit(Vehicle *v)
00993 {
00994   v->cur_image = SPR_ELECTRIC_SPARK_0;
00995   v->progress = 1;
00996 }
00997 
00998 static void ElectricSparkTick(Vehicle *v)
00999 {
01000   if (v->progress < 2) {
01001     v->progress++;
01002   } else {
01003     v->progress = 0;
01004     BeginVehicleMove(v);
01005     if (v->cur_image != SPR_ELECTRIC_SPARK_5) {
01006       v->cur_image++;
01007       VehiclePositionChanged(v);
01008       EndVehicleMove(v);
01009     } else {
01010       EndVehicleMove(v);
01011       delete v;
01012     }
01013   }
01014 }
01015 
01016 static void SmokeInit(Vehicle *v)
01017 {
01018   v->cur_image = SPR_SMOKE_0;
01019   v->progress = 12;
01020 }
01021 
01022 static void SmokeTick(Vehicle *v)
01023 {
01024   bool moved = false;
01025 
01026   BeginVehicleMove(v);
01027 
01028   v->progress++;
01029 
01030   if ((v->progress & 3) == 0) {
01031     v->z_pos++;
01032     moved = true;
01033   }
01034 
01035   if ((v->progress & 0xF) == 4) {
01036     if (v->cur_image != SPR_SMOKE_4) {
01037       v->cur_image++;
01038     } else {
01039       EndVehicleMove(v);
01040       delete v;
01041       return;
01042     }
01043     moved = true;
01044   }
01045 
01046   if (moved) {
01047     VehiclePositionChanged(v);
01048     EndVehicleMove(v);
01049   }
01050 }
01051 
01052 static void ExplosionLargeInit(Vehicle *v)
01053 {
01054   v->cur_image = SPR_EXPLOSION_LARGE_0;
01055   v->progress = 0;
01056 }
01057 
01058 static void ExplosionLargeTick(Vehicle *v)
01059 {
01060   v->progress++;
01061   if ((v->progress & 3) == 0) {
01062     BeginVehicleMove(v);
01063     if (v->cur_image != SPR_EXPLOSION_LARGE_F) {
01064       v->cur_image++;
01065       VehiclePositionChanged(v);
01066       EndVehicleMove(v);
01067     } else {
01068       EndVehicleMove(v);
01069       delete v;
01070     }
01071   }
01072 }
01073 
01074 static void BreakdownSmokeInit(Vehicle *v)
01075 {
01076   v->cur_image = SPR_BREAKDOWN_SMOKE_0;
01077   v->progress = 0;
01078 }
01079 
01080 static void BreakdownSmokeTick(Vehicle *v)
01081 {
01082   v->progress++;
01083   if ((v->progress & 7) == 0) {
01084     BeginVehicleMove(v);
01085     if (v->cur_image != SPR_BREAKDOWN_SMOKE_3) {
01086       v->cur_image++;
01087     } else {
01088       v->cur_image = SPR_BREAKDOWN_SMOKE_0;
01089     }
01090     VehiclePositionChanged(v);
01091     EndVehicleMove(v);
01092   }
01093 
01094   v->u.special.animation_state--;
01095   if (v->u.special.animation_state == 0) {
01096     BeginVehicleMove(v);
01097     EndVehicleMove(v);
01098     delete v;
01099   }
01100 }
01101 
01102 static void ExplosionSmallInit(Vehicle *v)
01103 {
01104   v->cur_image = SPR_EXPLOSION_SMALL_0;
01105   v->progress = 0;
01106 }
01107 
01108 static void ExplosionSmallTick(Vehicle *v)
01109 {
01110   v->progress++;
01111   if ((v->progress & 3) == 0) {
01112     BeginVehicleMove(v);
01113     if (v->cur_image != SPR_EXPLOSION_SMALL_B) {
01114       v->cur_image++;
01115       VehiclePositionChanged(v);
01116       EndVehicleMove(v);
01117     } else {
01118       EndVehicleMove(v);
01119       delete v;
01120     }
01121   }
01122 }
01123 
01124 static void BulldozerInit(Vehicle *v)
01125 {
01126   v->cur_image = SPR_BULLDOZER_NE;
01127   v->progress = 0;
01128   v->u.special.animation_state = 0;
01129   v->u.special.animation_substate = 0;
01130 }
01131 
01132 struct BulldozerMovement {
01133   byte direction:2;
01134   byte image:2;
01135   byte duration:3;
01136 };
01137 
01138 static const BulldozerMovement _bulldozer_movement[] = {
01139   { 0, 0, 4 },
01140   { 3, 3, 4 },
01141   { 2, 2, 7 },
01142   { 0, 2, 7 },
01143   { 1, 1, 3 },
01144   { 2, 2, 7 },
01145   { 0, 2, 7 },
01146   { 1, 1, 3 },
01147   { 2, 2, 7 },
01148   { 0, 2, 7 },
01149   { 3, 3, 6 },
01150   { 2, 2, 6 },
01151   { 1, 1, 7 },
01152   { 3, 1, 7 },
01153   { 0, 0, 3 },
01154   { 1, 1, 7 },
01155   { 3, 1, 7 },
01156   { 0, 0, 3 },
01157   { 1, 1, 7 },
01158   { 3, 1, 7 }
01159 };
01160 
01161 static const struct {
01162   int8 x;
01163   int8 y;
01164 } _inc_by_dir[] = {
01165   { -1,  0 },
01166   {  0,  1 },
01167   {  1,  0 },
01168   {  0, -1 }
01169 };
01170 
01171 static void BulldozerTick(Vehicle *v)
01172 {
01173   v->progress++;
01174   if ((v->progress & 7) == 0) {
01175     const BulldozerMovement* b = &_bulldozer_movement[v->u.special.animation_state];
01176 
01177     BeginVehicleMove(v);
01178 
01179     v->cur_image = SPR_BULLDOZER_NE + b->image;
01180 
01181     v->x_pos += _inc_by_dir[b->direction].x;
01182     v->y_pos += _inc_by_dir[b->direction].y;
01183 
01184     v->u.special.animation_substate++;
01185     if (v->u.special.animation_substate >= b->duration) {
01186       v->u.special.animation_substate = 0;
01187       v->u.special.animation_state++;
01188       if (v->u.special.animation_state == lengthof(_bulldozer_movement)) {
01189         EndVehicleMove(v);
01190         delete v;
01191         return;
01192       }
01193     }
01194     VehiclePositionChanged(v);
01195     EndVehicleMove(v);
01196   }
01197 }
01198 
01199 static void BubbleInit(Vehicle *v)
01200 {
01201   v->cur_image = SPR_BUBBLE_GENERATE_0;
01202   v->spritenum = 0;
01203   v->progress = 0;
01204 }
01205 
01206 struct BubbleMovement {
01207   int8 x:4;
01208   int8 y:4;
01209   int8 z:4;
01210   byte image:4;
01211 };
01212 
01213 #define MK(x, y, z, i) { x, y, z, i }
01214 #define ME(i) { i, 4, 0, 0 }
01215 
01216 static const BubbleMovement _bubble_float_sw[] = {
01217   MK(0, 0, 1, 0),
01218   MK(1, 0, 1, 1),
01219   MK(0, 0, 1, 0),
01220   MK(1, 0, 1, 2),
01221   ME(1)
01222 };
01223 
01224 
01225 static const BubbleMovement _bubble_float_ne[] = {
01226   MK( 0, 0, 1, 0),
01227   MK(-1, 0, 1, 1),
01228   MK( 0, 0, 1, 0),
01229   MK(-1, 0, 1, 2),
01230   ME(1)
01231 };
01232 
01233 static const BubbleMovement _bubble_float_se[] = {
01234   MK(0, 0, 1, 0),
01235   MK(0, 1, 1, 1),
01236   MK(0, 0, 1, 0),
01237   MK(0, 1, 1, 2),
01238   ME(1)
01239 };
01240 
01241 static const BubbleMovement _bubble_float_nw[] = {
01242   MK(0,  0, 1, 0),
01243   MK(0, -1, 1, 1),
01244   MK(0,  0, 1, 0),
01245   MK(0, -1, 1, 2),
01246   ME(1)
01247 };
01248 
01249 static const BubbleMovement _bubble_burst[] = {
01250   MK(0, 0, 1, 2),
01251   MK(0, 0, 1, 7),
01252   MK(0, 0, 1, 8),
01253   MK(0, 0, 1, 9),
01254   ME(0)
01255 };
01256 
01257 static const BubbleMovement _bubble_absorb[] = {
01258   MK(0, 0, 1, 0),
01259   MK(0, 0, 1, 1),
01260   MK(0, 0, 1, 0),
01261   MK(0, 0, 1, 2),
01262   MK(0, 0, 1, 0),
01263   MK(0, 0, 1, 1),
01264   MK(0, 0, 1, 0),
01265   MK(0, 0, 1, 2),
01266   MK(0, 0, 1, 0),
01267   MK(0, 0, 1, 1),
01268   MK(0, 0, 1, 0),
01269   MK(0, 0, 1, 2),
01270   MK(0, 0, 1, 0),
01271   MK(0, 0, 1, 1),
01272   MK(0, 0, 1, 0),
01273   MK(0, 0, 1, 2),
01274   MK(0, 0, 1, 0),
01275   MK(0, 0, 1, 1),
01276   MK(0, 0, 1, 0),
01277   MK(0, 0, 1, 2),
01278   MK(0, 0, 1, 0),
01279   MK(0, 0, 1, 1),
01280   MK(0, 0, 1, 0),
01281   MK(0, 0, 1, 2),
01282   MK(0, 0, 1, 0),
01283   MK(0, 0, 1, 1),
01284   MK(0, 0, 1, 0),
01285   MK(0, 0, 1, 2),
01286   MK(0, 0, 1, 0),
01287   MK(0, 0, 1, 1),
01288   MK(0, 0, 1, 0),
01289   MK(0, 0, 1, 2),
01290   MK(0, 0, 1, 0),
01291   MK(0, 0, 1, 1),
01292   MK(0, 0, 1, 0),
01293   MK(0, 0, 1, 2),
01294   MK(0, 0, 1, 0),
01295   MK(0, 0, 1, 1),
01296   MK(0, 0, 1, 0),
01297   MK(0, 0, 1, 2),
01298   MK(0, 0, 1, 0),
01299   MK(0, 0, 1, 1),
01300   MK(0, 0, 1, 0),
01301   MK(0, 0, 1, 2),
01302   MK(0, 0, 1, 0),
01303   MK(0, 0, 1, 1),
01304   MK(0, 0, 1, 0),
01305   MK(0, 0, 1, 2),
01306   MK(0, 0, 1, 0),
01307   MK(0, 0, 1, 1),
01308   MK(0, 0, 1, 0),
01309   MK(0, 0, 1, 2),
01310   MK(0, 0, 1, 0),
01311   MK(0, 0, 1, 1),
01312   MK(0, 0, 1, 0),
01313   MK(0, 0, 1, 2),
01314   MK(0, 0, 1, 0),
01315   MK(0, 0, 1, 1),
01316   MK(0, 0, 1, 0),
01317   MK(0, 0, 1, 2),
01318   MK(0, 0, 1, 0),
01319   MK(0, 0, 1, 1),
01320   MK(2, 1, 3, 0),
01321   MK(1, 1, 3, 1),
01322   MK(2, 1, 3, 0),
01323   MK(1, 1, 3, 2),
01324   MK(2, 1, 3, 0),
01325   MK(1, 1, 3, 1),
01326   MK(2, 1, 3, 0),
01327   MK(1, 0, 1, 2),
01328   MK(0, 0, 1, 0),
01329   MK(1, 0, 1, 1),
01330   MK(0, 0, 1, 0),
01331   MK(1, 0, 1, 2),
01332   MK(0, 0, 1, 0),
01333   MK(1, 0, 1, 1),
01334   MK(0, 0, 1, 0),
01335   MK(1, 0, 1, 2),
01336   ME(2),
01337   MK(0, 0, 0, 0xA),
01338   MK(0, 0, 0, 0xB),
01339   MK(0, 0, 0, 0xC),
01340   MK(0, 0, 0, 0xD),
01341   MK(0, 0, 0, 0xE),
01342   ME(0)
01343 };
01344 #undef ME
01345 #undef MK
01346 
01347 static const BubbleMovement * const _bubble_movement[] = {
01348   _bubble_float_sw,
01349   _bubble_float_ne,
01350   _bubble_float_se,
01351   _bubble_float_nw,
01352   _bubble_burst,
01353   _bubble_absorb,
01354 };
01355 
01356 static void BubbleTick(Vehicle *v)
01357 {
01358   uint et;
01359   const BubbleMovement *b;
01360 
01361   v->progress++;
01362   if ((v->progress & 3) != 0)
01363     return;
01364 
01365   BeginVehicleMove(v);
01366 
01367   if (v->spritenum == 0) {
01368     v->cur_image++;
01369     if (v->cur_image < SPR_BUBBLE_GENERATE_3) {
01370       VehiclePositionChanged(v);
01371       EndVehicleMove(v);
01372       return;
01373     }
01374     if (v->u.special.animation_substate != 0) {
01375       v->spritenum = GB(Random(), 0, 2) + 1;
01376     } else {
01377       v->spritenum = 6;
01378     }
01379     et = 0;
01380   } else {
01381     et = v->engine_type + 1;
01382   }
01383 
01384   b = &_bubble_movement[v->spritenum - 1][et];
01385 
01386   if (b->y == 4 && b->x == 0) {
01387     EndVehicleMove(v);
01388     delete v;
01389     return;
01390   }
01391 
01392   if (b->y == 4 && b->x == 1) {
01393     if (v->z_pos > 180 || Chance16I(1, 96, Random())) {
01394       v->spritenum = 5;
01395       SndPlayVehicleFx(SND_2F_POP, v);
01396     }
01397     et = 0;
01398   }
01399 
01400   if (b->y == 4 && b->x == 2) {
01401     TileIndex tile;
01402 
01403     et++;
01404     SndPlayVehicleFx(SND_31_EXTRACT, v);
01405 
01406     tile = TileVirtXY(v->x_pos, v->y_pos);
01407     if (IsTileType(tile, MP_INDUSTRY) && GetIndustryGfx(tile) == GFX_BUBBLE_CATCHER) AddAnimatedTile(tile);
01408   }
01409 
01410   v->engine_type = et;
01411   b = &_bubble_movement[v->spritenum - 1][et];
01412 
01413   v->x_pos += b->x;
01414   v->y_pos += b->y;
01415   v->z_pos += b->z;
01416   v->cur_image = SPR_BUBBLE_0 + b->image;
01417 
01418   VehiclePositionChanged(v);
01419   EndVehicleMove(v);
01420 }
01421 
01422 
01423 typedef void EffectInitProc(Vehicle *v);
01424 typedef void EffectTickProc(Vehicle *v);
01425 
01426 static EffectInitProc * const _effect_init_procs[] = {
01427   ChimneySmokeInit,
01428   SteamSmokeInit,
01429   DieselSmokeInit,
01430   ElectricSparkInit,
01431   SmokeInit,
01432   ExplosionLargeInit,
01433   BreakdownSmokeInit,
01434   ExplosionSmallInit,
01435   BulldozerInit,
01436   BubbleInit,
01437 };
01438 
01439 static EffectTickProc * const _effect_tick_procs[] = {
01440   ChimneySmokeTick,
01441   SteamSmokeTick,
01442   DieselSmokeTick,
01443   ElectricSparkTick,
01444   SmokeTick,
01445   ExplosionLargeTick,
01446   BreakdownSmokeTick,
01447   ExplosionSmallTick,
01448   BulldozerTick,
01449   BubbleTick,
01450 };
01451 
01452 
01453 Vehicle *CreateEffectVehicle(int x, int y, int z, EffectVehicle type)
01454 {
01455   Vehicle *v;
01456 
01457   v = new SpecialVehicle();
01458   if (v != NULL) {
01459     v->subtype = type;
01460     v->x_pos = x;
01461     v->y_pos = y;
01462     v->z_pos = z;
01463     v->tile = 0;
01464     v->UpdateDeltaXY(INVALID_DIR);
01465     v->vehstatus = VS_UNCLICKABLE;
01466 
01467     _effect_init_procs[type](v);
01468 
01469     VehiclePositionChanged(v);
01470     BeginVehicleMove(v);
01471     EndVehicleMove(v);
01472   }
01473   return v;
01474 }
01475 
01476 Vehicle *CreateEffectVehicleAbove(int x, int y, int z, EffectVehicle type)
01477 {
01478   int safe_x = Clamp(x, 0, MapMaxX() * TILE_SIZE);
01479   int safe_y = Clamp(y, 0, MapMaxY() * TILE_SIZE);
01480   return CreateEffectVehicle(x, y, GetSlopeZ(safe_x, safe_y) + z, type);
01481 }
01482 
01483 Vehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicle type)
01484 {
01485   return CreateEffectVehicle(v->x_pos + x, v->y_pos + y, v->z_pos + z, type);
01486 }
01487 
01488 void SpecialVehicle::Tick()
01489 {
01490   _effect_tick_procs[this->subtype](this);
01491 }
01492 
01493 Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y)
01494 {
01495   Vehicle *found = NULL, *v;
01496   uint dist, best_dist = (uint)-1;
01497 
01498   if ( (uint)(x -= vp->left) >= (uint)vp->width ||
01499        (uint)(y -= vp->top) >= (uint)vp->height)
01500         return NULL;
01501 
01502   x = ScaleByZoom(x, vp->zoom) + vp->virtual_left;
01503   y = ScaleByZoom(y, vp->zoom) + vp->virtual_top;
01504 
01505   FOR_ALL_VEHICLES(v) {
01506     if ((v->vehstatus & (VS_HIDDEN|VS_UNCLICKABLE)) == 0 &&
01507         x >= v->left_coord && x <= v->right_coord &&
01508         y >= v->top_coord && y <= v->bottom_coord) {
01509 
01510       dist = max(
01511         abs( ((v->left_coord + v->right_coord)>>1) - x ),
01512         abs( ((v->top_coord + v->bottom_coord)>>1) - y )
01513       );
01514 
01515       if (dist < best_dist) {
01516         found = v;
01517         best_dist = dist;
01518       }
01519     }
01520   }
01521 
01522   return found;
01523 }
01524 
01525 void CheckVehicle32Day(Vehicle *v)
01526 {
01527   if ((v->day_counter & 0x1F) != 0) return;
01528 
01529   uint16 callback = GetVehicleCallback(CBID_VEHICLE_32DAY_CALLBACK, 0, 0, v->engine_type, v);
01530   if (callback == CALLBACK_FAILED) return;
01531   if (HasBit(callback, 0)) TriggerVehicle(v, VEHICLE_TRIGGER_CALLBACK_32); // Trigger vehicle trigger 10
01532   if (HasBit(callback, 1)) v->colormap = PAL_NONE;                         // Update colormap via callback 2D
01533 }
01534 
01535 void DecreaseVehicleValue(Vehicle *v)
01536 {
01537   v->value -= v->value >> 8;
01538   InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
01539 }
01540 
01541 static const byte _breakdown_chance[64] = {
01542     3,   3,   3,   3,   3,   3,   3,   3,
01543     4,   4,   5,   5,   6,   6,   7,   7,
01544     8,   8,   9,   9,  10,  10,  11,  11,
01545    12,  13,  13,  13,  13,  14,  15,  16,
01546    17,  19,  21,  25,  28,  31,  34,  37,
01547    40,  44,  48,  52,  56,  60,  64,  68,
01548    72,  80,  90, 100, 110, 120, 130, 140,
01549   150, 170, 190, 210, 230, 250, 250, 250,
01550 };
01551 
01552 void CheckVehicleBreakdown(Vehicle *v)
01553 {
01554   int rel, rel_old;
01555   uint32 r;
01556   int chance;
01557 
01558   /* decrease reliability */
01559   v->reliability = rel = max((rel_old = v->reliability) - v->reliability_spd_dec, 0);
01560   if ((rel_old >> 8) != (rel >> 8))
01561     InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
01562 
01563   if (v->breakdown_ctr != 0 || v->vehstatus & VS_STOPPED ||
01564       v->cur_speed < 5 || _game_mode == GM_MENU) {
01565     return;
01566   }
01567 
01568   r = Random();
01569 
01570   /* increase chance of failure */
01571   chance = v->breakdown_chance + 1;
01572   if (Chance16I(1,25,r)) chance += 25;
01573   v->breakdown_chance = min(255, chance);
01574 
01575   /* calculate reliability value to use in comparison */
01576   rel = v->reliability;
01577   if (v->type == VEH_SHIP) rel += 0x6666;
01578 
01579   /* disabled breakdowns? */
01580   if (_opt.diff.vehicle_breakdowns < 1) return;
01581 
01582   /* reduced breakdowns? */
01583   if (_opt.diff.vehicle_breakdowns == 1) rel += 0x6666;
01584 
01585   /* check if to break down */
01586   if (_breakdown_chance[(uint)min(rel, 0xffff) >> 10] <= v->breakdown_chance) {
01587     v->breakdown_ctr    = GB(r, 16, 6) + 0x3F;
01588     v->breakdown_delay  = GB(r, 24, 7) + 0x80;
01589     v->breakdown_chance = 0;
01590   }
01591 }
01592 
01593 static const StringID _vehicle_type_names[4] = {
01594   STR_019F_TRAIN,
01595   STR_019C_ROAD_VEHICLE,
01596   STR_019E_SHIP,
01597   STR_019D_AIRCRAFT,
01598 };
01599 
01600 static void ShowVehicleGettingOld(Vehicle *v, StringID msg)
01601 {
01602   if (v->owner != _local_player) return;
01603 
01604   /* Do not show getting-old message if autorenew is active (and it can replace the vehicle) */
01605   if (GetPlayer(v->owner)->engine_renew && GetEngine(v->engine_type)->player_avail != 0) return;
01606 
01607   SetDParam(0, _vehicle_type_names[v->type]);
01608   SetDParam(1, v->unitnumber);
01609   AddNewsItem(msg, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0);
01610 }
01611 
01612 void AgeVehicle(Vehicle *v)
01613 {
01614   if (v->age < 65535) v->age++;
01615 
01616   int age = v->age - v->max_age;
01617   if (age == 366*0 || age == 366*1 || age == 366*2 || age == 366*3 || age == 366*4) v->reliability_spd_dec <<= 1;
01618 
01619   InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
01620 
01621   if (age == -366) {
01622     ShowVehicleGettingOld(v, STR_01A0_IS_GETTING_OLD);
01623   } else if (age == 0) {
01624     ShowVehicleGettingOld(v, STR_01A1_IS_GETTING_VERY_OLD);
01625   } else if (age > 0 && (age % 366) == 0) {
01626     ShowVehicleGettingOld(v, STR_01A2_IS_GETTING_VERY_OLD_AND);
01627   }
01628 }
01629 
01640 CommandCost CmdMassStartStopVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
01641 {
01642   Vehicle **vl = NULL;
01643   uint16 engine_list_length = 0;
01644   uint16 engine_count = 0;
01645   CommandCost return_value = CMD_ERROR;
01646   uint i;
01647   uint stop_command;
01648   VehicleType vehicle_type = (VehicleType)GB(p2, 0, 5);
01649   bool start_stop = HasBit(p2, 5);
01650   bool vehicle_list_window = HasBit(p2, 6);
01651 
01652   switch (vehicle_type) {
01653     case VEH_TRAIN:    stop_command = CMD_START_STOP_TRAIN;    break;
01654     case VEH_ROAD:     stop_command = CMD_START_STOP_ROADVEH;  break;
01655     case VEH_SHIP:     stop_command = CMD_START_STOP_SHIP;     break;
01656     case VEH_AIRCRAFT: stop_command = CMD_START_STOP_AIRCRAFT; break;
01657     default: return CMD_ERROR;
01658   }
01659 
01660   if (vehicle_list_window) {
01661     uint32 id = p1;
01662     uint16 window_type = p2 & VLW_MASK;
01663 
01664     engine_count = GenerateVehicleSortList((const Vehicle***)&vl, &engine_list_length, vehicle_type, _current_player, id, window_type);
01665   } else {
01666     /* Get the list of vehicles in the depot */
01667     BuildDepotVehicleList(vehicle_type, tile, &vl, &engine_list_length, &engine_count, NULL, NULL, NULL);
01668   }
01669 
01670   for (i = 0; i < engine_count; i++) {
01671     const Vehicle *v = vl[i];
01672     CommandCost ret;
01673 
01674     if (!!(v->vehstatus & VS_STOPPED) != start_stop) continue;
01675 
01676     if (!vehicle_list_window) {
01677       if (vehicle_type == VEH_TRAIN) {
01678         if (CheckTrainInDepot(v, false) == -1) continue;
01679       } else {
01680         if (!(v->vehstatus & VS_HIDDEN)) continue;
01681       }
01682     }
01683 
01684     ret = DoCommand(tile, v->index, 0, flags, stop_command);
01685 
01686     if (CmdSucceeded(ret)) {
01687       return_value = CommandCost();
01688       /* We know that the command is valid for at least one vehicle.
01689        * If we haven't set DC_EXEC, then there is no point in continueing because it will be valid */
01690       if (!(flags & DC_EXEC)) break;
01691     }
01692   }
01693 
01694   free(vl);
01695   return return_value;
01696 }
01697 
01704 CommandCost CmdDepotSellAllVehicles(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
01705 {
01706   Vehicle **engines = NULL;
01707   Vehicle **wagons = NULL;
01708   uint16 engine_list_length = 0;
01709   uint16 engine_count = 0;
01710   uint16 wagon_list_length = 0;
01711   uint16 wagon_count = 0;
01712 
01713   CommandCost cost(EXPENSES_NEW_VEHICLES);
01714   uint i, sell_command, total_number_vehicles;
01715   VehicleType vehicle_type = (VehicleType)GB(p1, 0, 8);
01716 
01717   switch (vehicle_type) {
01718     case VEH_TRAIN:    sell_command = CMD_SELL_RAIL_WAGON; break;
01719     case VEH_ROAD:     sell_command = CMD_SELL_ROAD_VEH;   break;
01720     case VEH_SHIP:     sell_command = CMD_SELL_SHIP;       break;
01721     case VEH_AIRCRAFT: sell_command = CMD_SELL_AIRCRAFT;   break;
01722     default: return CMD_ERROR;
01723   }
01724 
01725   /* Get the list of vehicles in the depot */
01726   BuildDepotVehicleList(vehicle_type, tile, &engines, &engine_list_length, &engine_count,
01727                                   &wagons,  &wagon_list_length,  &wagon_count);
01728 
01729   total_number_vehicles = engine_count + wagon_count;
01730   for (i = 0; i < total_number_vehicles; i++) {
01731     const Vehicle *v;
01732     CommandCost ret;
01733 
01734     if (i < engine_count) {
01735       v = engines[i];
01736     } else {
01737       v = wagons[i - engine_count];
01738     }
01739 
01740     ret = DoCommand(tile, v->index, 1, flags, sell_command);
01741 
01742     if (CmdSucceeded(ret)) cost.AddCost(ret);
01743   }
01744 
01745   free(engines);
01746   free(wagons);
01747   if (cost.GetCost() == 0) return CMD_ERROR; // no vehicles to sell
01748   return cost;
01749 }
01750 
01757 CommandCost CmdDepotMassAutoReplace(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
01758 {
01759   Vehicle **vl = NULL;
01760   uint16 engine_list_length = 0;
01761   uint16 engine_count = 0;
01762   uint i, x = 0, y = 0, z = 0;
01763   CommandCost cost;
01764   VehicleType vehicle_type = (VehicleType)GB(p1, 0, 8);
01765 
01766   if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_player)) return CMD_ERROR;
01767 
01768   /* Get the list of vehicles in the depot */
01769   BuildDepotVehicleList(vehicle_type, tile, &vl, &engine_list_length, &engine_count, NULL, NULL, NULL);
01770 
01771 
01772   for (i = 0; i < engine_count; i++) {
01773     Vehicle *v = vl[i];
01774     bool stopped = !(v->vehstatus & VS_STOPPED);
01775     CommandCost ret;
01776 
01777     /* Ensure that the vehicle completely in the depot */
01778     if (!v->IsInDepot()) continue;
01779 
01780     x = v->x_pos;
01781     y = v->y_pos;
01782     z = v->z_pos;
01783 
01784     if (stopped) {
01785       v->vehstatus |= VS_STOPPED; // Stop the vehicle
01786       v->leave_depot_instantly = true;
01787     }
01788     ret = MaybeReplaceVehicle(v, !(flags & DC_EXEC), false);
01789 
01790     if (CmdSucceeded(ret)) {
01791       cost.AddCost(ret);
01792       if (!(flags & DC_EXEC)) break;
01793       /* There is a problem with autoreplace and newgrf
01794        * It's impossible to tell the length of a train after it's being replaced before it's actually done
01795        * Because of this, we can't estimate costs due to wagon removal and we will have to always return 0 and pay manually
01796        * Since we pay after each vehicle is replaced and MaybeReplaceVehicle() check if the player got enough money
01797        * we should never reach a condition where the player will end up with negative money from doing this */
01798       SubtractMoneyFromPlayer(ret);
01799     }
01800   }
01801 
01802   if (cost.GetCost() == 0) {
01803     cost = CMD_ERROR;
01804   } else {
01805     if (flags & DC_EXEC) {
01806       /* Display the cost animation now that DoCommandP() can't do it for us (see previous comments) */
01807       if (IsLocalPlayer()) ShowCostOrIncomeAnimation(x, y, z, cost.GetCost());
01808     }
01809     cost = CommandCost();
01810   }
01811 
01812   free(vl);
01813   return cost;
01814 }
01815 
01822 CommandCost CmdCloneVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
01823 {
01824   Vehicle *v_front, *v;
01825   Vehicle *w_front, *w, *w_rear;
01826   CommandCost cost, total_cost(EXPENSES_NEW_VEHICLES);
01827   uint32 build_argument = 2;
01828 
01829   if (!IsValidVehicleID(p1)) return CMD_ERROR;
01830   v = GetVehicle(p1);
01831   v_front = v;
01832   w = NULL;
01833   w_front = NULL;
01834   w_rear = NULL;
01835 
01836 
01837   /*
01838    * v_front is the front engine in the original vehicle
01839    * v is the car/vehicle of the original vehicle, that is currently being copied
01840    * w_front is the front engine of the cloned vehicle
01841    * w is the car/vehicle currently being cloned
01842    * w_rear is the rear end of the cloned train. It's used to add more cars and is only used by trains
01843    */
01844 
01845   if (!CheckOwnership(v->owner)) return CMD_ERROR;
01846 
01847   if (v->type == VEH_TRAIN && (!IsFrontEngine(v) || v->u.rail.crash_anim_pos >= 4400)) return CMD_ERROR;
01848 
01849   /* check that we can allocate enough vehicles */
01850   if (!(flags & DC_EXEC)) {
01851     int veh_counter = 0;
01852     do {
01853       veh_counter++;
01854     } while ((v = v->Next()) != NULL);
01855 
01856     if (!Vehicle::AllocateList(NULL, veh_counter)) {
01857       return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
01858     }
01859   }
01860 
01861   v = v_front;
01862 
01863   do {
01864     if (v->type == VEH_TRAIN && IsRearDualheaded(v)) {
01865       /* we build the rear ends of multiheaded trains with the front ones */
01866       continue;
01867     }
01868 
01869     cost = DoCommand(tile, v->engine_type, build_argument, flags, GetCmdBuildVeh(v));
01870     build_argument = 3; // ensure that we only assign a number to the first engine
01871 
01872     if (CmdFailed(cost)) return cost;
01873 
01874     total_cost.AddCost(cost);
01875 
01876     if (flags & DC_EXEC) {
01877       w = GetVehicle(_new_vehicle_id);
01878 
01879       if (v->type == VEH_TRAIN && HasBit(v->u.rail.flags, VRF_REVERSE_DIRECTION)) {
01880         SetBit(w->u.rail.flags, VRF_REVERSE_DIRECTION);
01881       }
01882 
01883       if (v->type == VEH_TRAIN && !IsFrontEngine(v)) {
01884         /* this s a train car
01885          * add this unit to the end of the train */
01886         CommandCost result = DoCommand(0, (w_rear->index << 16) | w->index, 1, flags, CMD_MOVE_RAIL_VEHICLE);
01887         if (CmdFailed(result)) {
01888           /* The train can't be joined to make the same consist as the original.
01889            * Sell what we already made (clean up) and return an error.           */
01890           DoCommand(w_front->tile, w_front->index, 1, flags, GetCmdSellVeh(w_front));
01891           DoCommand(w_front->tile, w->index,       1, flags, GetCmdSellVeh(w));
01892           return result; // return error and the message returned from CMD_MOVE_RAIL_VEHICLE
01893         }
01894       } else {
01895         /* this is a front engine or not a train. */
01896         w_front = w;
01897         w->service_interval = v->service_interval;
01898       }
01899       w_rear = w; // trains needs to know the last car in the train, so they can add more in next loop
01900     }
01901   } while (v->type == VEH_TRAIN && (v = GetNextVehicle(v)) != NULL);
01902 
01903   if (flags & DC_EXEC && v_front->type == VEH_TRAIN) {
01904     /* for trains this needs to be the front engine due to the callback function */
01905     _new_vehicle_id = w_front->index;
01906   }
01907 
01908   if (flags & DC_EXEC) {
01909     /* Cloned vehicles belong to the same group */
01910     DoCommand(0, v_front->group_id, w_front->index, flags, CMD_ADD_VEHICLE_GROUP);
01911   }
01912 
01913 
01914   /* Take care of refitting. */
01915   w = w_front;
01916   v = v_front;
01917 
01918   /* Both building and refitting are influenced by newgrf callbacks, which
01919    * makes it impossible to accurately estimate the cloning costs. In
01920    * particular, it is possible for engines of the same type to be built with
01921    * different numbers of articulated parts, so when refitting we have to
01922    * loop over real vehicles first, and then the articulated parts of those
01923    * vehicles in a different loop. */
01924   do {
01925     do {
01926       if (flags & DC_EXEC) {
01927         assert(w != NULL);
01928 
01929         if (w->cargo_type != v->cargo_type || w->cargo_subtype != v->cargo_subtype) {
01930           cost = DoCommand(0, w->index, v->cargo_type | (v->cargo_subtype << 8) | 1U << 16 , flags, GetCmdRefitVeh(v));
01931           if (CmdSucceeded(cost)) total_cost.AddCost(cost);
01932         }
01933 
01934         if (w->type == VEH_TRAIN && EngineHasArticPart(w)) {
01935           w = GetNextArticPart(w);
01936         } else if (w->type == VEH_ROAD && RoadVehHasArticPart(w)) {
01937           w = w->Next();
01938         } else {
01939           break;
01940         }
01941       } else {
01942         CargoID initial_cargo = GetEngineCargoType(v->engine_type);
01943 
01944         if (v->cargo_type != initial_cargo && initial_cargo != CT_INVALID) {
01945           total_cost.AddCost(GetRefitCost(v->engine_type));
01946         }
01947       }
01948 
01949       if (v->type == VEH_TRAIN && EngineHasArticPart(v)) {
01950         v = GetNextArticPart(v);
01951       } else if (v->type == VEH_ROAD && RoadVehHasArticPart(v)) {
01952         v = v->Next();
01953       } else {
01954         break;
01955       }
01956     } while (v != NULL);
01957 
01958     if ((flags & DC_EXEC) && v->type == VEH_TRAIN) w = GetNextVehicle(w);
01959   } while (v->type == VEH_TRAIN && (v = GetNextVehicle(v)) != NULL);
01960 
01961   if (flags & DC_EXEC) {
01962     /*
01963      * Set the orders of the vehicle. Cannot do it earlier as we need
01964      * the vehicle refitted before doing this, otherwise the moved
01965      * cargo types might not match (passenger vs non-passenger)
01966      */
01967     DoCommand(0, (v_front->index << 16) | w_front->index, p2 & 1 ? CO_SHARE : CO_COPY, flags, CMD_CLONE_ORDER);
01968   }
01969 
01970   /* Since we can't estimate the cost of cloning a vehicle accurately we must
01971    * check whether the player has enough money manually. */
01972   if (!CheckPlayerHasMoney(total_cost)) {
01973     if (flags & DC_EXEC) {
01974       /* The vehicle has already been bought, so now it must be sold again. */
01975       DoCommand(w_front->tile, w_front->index, 1, flags, GetCmdSellVeh(w_front));
01976     }
01977     return CMD_ERROR;
01978   }
01979 
01980   return total_cost;
01981 }
01982 
01983 
01984 /* Extend the list size for BuildDepotVehicleList() */
01985 static inline void ExtendVehicleListSize(const Vehicle ***engine_list, uint16 *engine_list_length, uint16 step_size)
01986 {
01987   *engine_list_length = min(*engine_list_length + step_size, GetMaxVehicleIndex() + 1);
01988   *engine_list = ReallocT(*engine_list, *engine_list_length);
01989 }
01990 
02003 void BuildDepotVehicleList(VehicleType type, TileIndex tile, Vehicle ***engine_list, uint16 *engine_list_length, uint16 *engine_count, Vehicle ***wagon_list, uint16 *wagon_list_length, uint16 *wagon_count)
02004 {
02005   Vehicle *v;
02006 
02007   /* This function should never be called without an array to store results */
02008   assert(!(engine_list == NULL && type != VEH_TRAIN));
02009   assert(!(type == VEH_TRAIN && engine_list == NULL && wagon_list == NULL));
02010 
02011   /* Both array and the length should either be NULL to disable the list or both should not be NULL */
02012   assert((engine_list == NULL && engine_list_length == NULL) || (engine_list != NULL && engine_list_length != NULL));
02013   assert((wagon_list == NULL && wagon_list_length == NULL) || (wagon_list != NULL && wagon_list_length != NULL));
02014 
02015   assert(!(engine_list != NULL && engine_count == NULL));
02016   assert(!(wagon_list != NULL && wagon_count == NULL));
02017 
02018   if (engine_count != NULL) *engine_count = 0;
02019   if (wagon_count != NULL) *wagon_count = 0;
02020 
02021   switch (type) {
02022     case VEH_TRAIN:
02023       FOR_ALL_VEHICLES(v) {
02024         if (v->tile == tile && v->type == VEH_TRAIN && v->u.rail.track == TRACK_BIT_DEPOT) {
02025           if (IsFrontEngine(v)) {
02026             if (engine_list == NULL) continue;
02027             if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25);
02028             (*engine_list)[(*engine_count)++] = v;
02029           } else if (IsFreeWagon(v)) {
02030             if (wagon_list == NULL) continue;
02031             if (*wagon_count == *wagon_list_length) ExtendVehicleListSize((const Vehicle***)wagon_list, wagon_list_length, 25);
02032             (*wagon_list)[(*wagon_count)++] = v;
02033           }
02034         }
02035       }
02036       break;
02037 
02038     case VEH_ROAD:
02039       FOR_ALL_VEHICLES(v) {
02040         if (v->tile == tile && v->type == VEH_ROAD && v->IsInDepot() && IsRoadVehFront(v)) {
02041           if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25);
02042           (*engine_list)[(*engine_count)++] = v;
02043         }
02044       }
02045       break;
02046 
02047     case VEH_SHIP:
02048       FOR_ALL_VEHICLES(v) {
02049         if (v->tile == tile && v->type == VEH_SHIP && v->IsInDepot()) {
02050           if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25);
02051           (*engine_list)[(*engine_count)++] = v;
02052         }
02053       }
02054       break;
02055 
02056     case VEH_AIRCRAFT:
02057       FOR_ALL_VEHICLES(v) {
02058         if (v->tile == tile &&
02059             v->type == VEH_AIRCRAFT && IsNormalAircraft(v) &&
02060             v->IsInDepot()) {
02061           if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25);
02062           (*engine_list)[(*engine_count)++] = v;
02063         }
02064       }
02065       break;
02066 
02067     default: NOT_REACHED();
02068   }
02069 }
02070 
02087 uint GenerateVehicleSortList(const Vehicle ***sort_list, uint16 *length_of_array, VehicleType type, PlayerID owner, uint32 index, uint16 window_type)
02088 {
02089   uint n = 0;
02090   const Vehicle *v;
02091 
02092   switch (window_type) {
02093     case VLW_STATION_LIST: {
02094       FOR_ALL_VEHICLES(v) {
02095         if (v->type == type && v->IsPrimaryVehicle()) {
02096           const Order *order;
02097 
02098           FOR_VEHICLE_ORDERS(v, order) {
02099             if (order->type == OT_GOTO_STATION && order->dest == index) {
02100               if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 50);
02101               (*sort_list)[n++] = v;
02102               break;
02103             }
02104           }
02105         }
02106       }
02107       break;
02108     }
02109 
02110     case VLW_SHARED_ORDERS: {
02111       FOR_ALL_VEHICLES(v) {
02112         /* Find a vehicle with the order in question */
02113         if (v->orders != NULL && v->orders->index == index) break;
02114       }
02115 
02116       if (v != NULL && v->orders != NULL && v->orders->index == index) {
02117         /* Only try to make the list if we found a vehicle using the order in question */
02118         for (v = GetFirstVehicleFromSharedList(v); v != NULL; v = v->next_shared) {
02119           if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 25);
02120           (*sort_list)[n++] = v;
02121         }
02122       }
02123       break;
02124     }
02125 
02126     case VLW_STANDARD: {
02127       FOR_ALL_VEHICLES(v) {
02128         if (v->type == type && v->owner == owner && v->IsPrimaryVehicle()) {
02129           /* TODO find a better estimate on the total number of vehicles for current player */
02130           if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, GetNumVehicles()/4);
02131           (*sort_list)[n++] = v;
02132         }
02133       }
02134       break;
02135     }
02136 
02137     case VLW_DEPOT_LIST: {
02138       FOR_ALL_VEHICLES(v) {
02139         if (v->type == type && v->IsPrimaryVehicle()) {
02140           const Order *order;
02141 
02142           FOR_VEHICLE_ORDERS(v, order) {
02143             if (order->type == OT_GOTO_DEPOT && order->dest == index) {
02144               if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 25);
02145               (*sort_list)[n++] = v;
02146               break;
02147             }
02148           }
02149         }
02150       }
02151       break;
02152     }
02153 
02154     case VLW_GROUP_LIST:
02155       FOR_ALL_VEHICLES(v) {
02156         if (v->type == type && v->IsPrimaryVehicle() &&
02157             v->owner == owner && v->group_id == index) {
02158           if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, GetNumVehicles() / 4);
02159 
02160           (*sort_list)[n++] = v;
02161         }
02162       }
02163       break;
02164 
02165     default: NOT_REACHED(); break;
02166   }
02167 
02168   if ((n + 100) < *length_of_array) {
02169     /* We allocated way too much for sort_list.
02170      * Now we will reduce how much we allocated.
02171      * We will still make it have room for 50 extra vehicles to prevent having
02172      * to move the whole array if just one vehicle is added later */
02173     *length_of_array = n + 50;
02174     *sort_list = ReallocT(*sort_list, (*length_of_array) * sizeof((*sort_list)[0]));
02175   }
02176 
02177   return n;
02178 }
02179 
02188 CommandCost SendAllVehiclesToDepot(VehicleType type, uint32 flags, bool service, PlayerID owner, uint16 vlw_flag, uint32 id)
02189 {
02190   const Vehicle **sort_list = NULL;
02191   uint n, i;
02192   uint16 array_length = 0;
02193 
02194   n = GenerateVehicleSortList(&sort_list, &array_length, type, owner, id, vlw_flag);
02195 
02196   /* Send all the vehicles to a depot */
02197   for (i = 0; i < n; i++) {
02198     const Vehicle *v = sort_list[i];
02199     CommandCost ret = DoCommand(v->tile, v->index, (service ? 1 : 0) | DEPOT_DONT_CANCEL, flags, GetCmdSendToDepot(type));
02200 
02201     /* Return 0 if DC_EXEC is not set this is a valid goto depot command)
02202       * In this case we know that at least one vehicle can be sent to a depot
02203       * and we will issue the command. We can now safely quit the loop, knowing
02204       * it will succeed at least once. With DC_EXEC we really need to send them to the depot */
02205     if (CmdSucceeded(ret) && !(flags & DC_EXEC)) {
02206       free((void*)sort_list);
02207       return CommandCost();
02208     }
02209   }
02210 
02211   free((void*)sort_list);
02212   return (flags & DC_EXEC) ? CommandCost() : CMD_ERROR;
02213 }
02214 
02221 uint8 CalcPercentVehicleFilled(Vehicle *v, StringID *color)
02222 {
02223   int count = 0;
02224   int max = 0;
02225   int cars = 0;
02226   int unloading = 0;
02227   bool loading = false;
02228 
02229   assert(color != NULL);
02230 
02231   const Vehicle *u = v;
02232   const Station *st = GetStation(v->last_station_visited);
02233 
02234   /* Count up max and used */
02235   for (; v != NULL; v = v->Next()) {
02236     count += v->cargo.Count();
02237     max += v->cargo_cap;
02238     if (v->cargo_cap != 0) {
02239       unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0;
02240       loading |= (u->current_order.flags & OFB_UNLOAD) == 0 && st->goods[v->cargo_type].days_since_pickup != 255;
02241       cars++;
02242     }
02243   }
02244 
02245   if (unloading == 0 && loading)          *color = STR_PERCENT_UP;
02246   else if (cars == unloading || !loading) *color = STR_PERCENT_DOWN;
02247   else                                    *color = STR_PERCENT_UP_DOWN;
02248 
02249   /* Train without capacity */
02250   if (max == 0) return 100;
02251 
02252   /* Return the percentage */
02253   return (count * 100) / max;
02254 }
02255 
02256 void VehicleEnterDepot(Vehicle *v)
02257 {
02258   switch (v->type) {
02259     case VEH_TRAIN:
02260       InvalidateWindowClasses(WC_TRAINS_LIST);
02261       if (!IsFrontEngine(v)) v = v->First();
02262       UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner);
02263       v->load_unload_time_rem = 0;
02264       /* Reset reversed flag */
02265       for (Vehicle *u = v; u != NULL; u = u->Next()) ClrBit(u->u.rail.flags, VRF_TOGGLE_REVERSE);
02266       TrainConsistChanged(v, true);
02267       break;
02268 
02269     case VEH_ROAD:
02270       InvalidateWindowClasses(WC_ROADVEH_LIST);
02271       if (!IsRoadVehFront(v)) v = v->First();
02272       break;
02273 
02274     case VEH_SHIP:
02275       InvalidateWindowClasses(WC_SHIPS_LIST);
02276       v->u.ship.state = TRACK_BIT_DEPOT;
02277       RecalcShipStuff(v);
02278       break;
02279 
02280     case VEH_AIRCRAFT:
02281       InvalidateWindowClasses(WC_AIRCRAFT_LIST);
02282       HandleAircraftEnterHangar(v);
02283       break;
02284     default: NOT_REACHED();
02285   }
02286 
02287   if (v->type != VEH_TRAIN) {
02288     /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
02289      * 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 */
02290     InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
02291   }
02292   InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
02293 
02294   v->vehstatus |= VS_HIDDEN;
02295   v->cur_speed = 0;
02296 
02297   VehicleServiceInDepot(v);
02298 
02299   TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
02300 
02301   if (v->current_order.type == OT_GOTO_DEPOT) {
02302     Order t;
02303 
02304     InvalidateWindow(WC_VEHICLE_VIEW, v->index);
02305 
02306     t = v->current_order;
02307     v->current_order.type = OT_DUMMY;
02308     v->current_order.flags = 0;
02309 
02310     if (t.refit_cargo < NUM_CARGO) {
02311       CommandCost cost;
02312 
02313       _current_player = v->owner;
02314       cost = DoCommand(v->tile, v->index, t.refit_cargo | t.refit_subtype << 8, DC_EXEC, GetCmdRefitVeh(v));
02315 
02316       if (CmdFailed(cost)) {
02317         v->leave_depot_instantly = false; // We ensure that the vehicle stays in the depot
02318         if (v->owner == _local_player) {
02319           /* Notify the user that we stopped the vehicle */
02320           SetDParam(0, _vehicle_type_names[v->type]);
02321           SetDParam(1, v->unitnumber);
02322           AddNewsItem(STR_ORDER_REFIT_FAILED, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0);
02323         }
02324       } else if (v->owner == _local_player && cost.GetCost() != 0) {
02325         ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
02326       }
02327     }
02328 
02329     if (HasBit(t.flags, OF_PART_OF_ORDERS)) {
02330       /* Part of orders */
02331       UpdateVehicleTimetable(v, true);
02332       v->cur_order_index++;
02333     } else if (HasBit(t.flags, OF_HALT_IN_DEPOT)) {
02334       /* Force depot visit */
02335       v->vehstatus |= VS_STOPPED;
02336       if (v->owner == _local_player) {
02337         StringID string;
02338 
02339         switch (v->type) {
02340           case VEH_TRAIN:    string = STR_8814_TRAIN_IS_WAITING_IN_DEPOT; break;
02341           case VEH_ROAD:     string = STR_9016_ROAD_VEHICLE_IS_WAITING;   break;
02342           case VEH_SHIP:     string = STR_981C_SHIP_IS_WAITING_IN_DEPOT;  break;
02343           case VEH_AIRCRAFT: string = STR_A014_AIRCRAFT_IS_WAITING_IN;    break;
02344           default: NOT_REACHED(); string = STR_EMPTY; // Set the string to something to avoid a compiler warning
02345         }
02346 
02347         SetDParam(0, v->unitnumber);
02348         AddNewsItem(string, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0);
02349       }
02350     }
02351   }
02352 }
02353 
02354 static bool IsUniqueVehicleName(const char *name)
02355 {
02356   const Vehicle *v;
02357   char buf[512];
02358 
02359   FOR_ALL_VEHICLES(v) {
02360     switch (v->type) {
02361       case VEH_TRAIN:
02362         if (!IsTrainEngine(v)) continue;
02363         break;
02364 
02365       case VEH_ROAD:
02366         if (!IsRoadVehFront(v)) continue;
02367         break;
02368 
02369       case VEH_AIRCRAFT:
02370         if (!IsNormalAircraft(v)) continue;
02371         break;
02372 
02373       case VEH_SHIP:
02374         break;
02375 
02376       default:
02377         continue;
02378     }
02379 
02380     SetDParam(0, v->index);
02381     GetString(buf, STR_VEHICLE_NAME, lastof(buf));
02382     if (strcmp(buf, name) == 0) return false;
02383   }
02384 
02385   return true;
02386 }
02387 
02394 CommandCost CmdNameVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
02395 {
02396   Vehicle *v;
02397 
02398   if (!IsValidVehicleID(p1) || StrEmpty(_cmd_text)) return CMD_ERROR;
02399 
02400   v = GetVehicle(p1);
02401 
02402   if (!CheckOwnership(v->owner)) return CMD_ERROR;
02403 
02404   if (!IsUniqueVehicleName(_cmd_text)) return_cmd_error(STR_NAME_MUST_BE_UNIQUE);
02405 
02406   if (flags & DC_EXEC) {
02407     free(v->name);
02408     v->name = strdup(_cmd_text);
02409     ResortVehicleLists();
02410     MarkWholeScreenDirty();
02411   }
02412 
02413   return CommandCost();
02414 }
02415 
02416 
02423 CommandCost CmdChangeServiceInt(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
02424 {
02425   Vehicle* v;
02426   uint16 serv_int = GetServiceIntervalClamped(p2); /* Double check the service interval from the user-input */
02427 
02428   if (serv_int != p2 || !IsValidVehicleID(p1)) return CMD_ERROR;
02429 
02430   v = GetVehicle(p1);
02431 
02432   if (!CheckOwnership(v->owner)) return CMD_ERROR;
02433 
02434   if (flags & DC_EXEC) {
02435     v->service_interval = serv_int;
02436     InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
02437   }
02438 
02439   return CommandCost();
02440 }
02441 
02442 
02443 static Rect _old_vehicle_coords; 
02444 
02451 void BeginVehicleMove(const Vehicle *v)
02452 {
02453   _old_vehicle_coords.left   = v->left_coord;
02454   _old_vehicle_coords.top    = v->top_coord;
02455   _old_vehicle_coords.right  = v->right_coord;
02456   _old_vehicle_coords.bottom = v->bottom_coord;
02457 }
02458 
02465 void EndVehicleMove(const Vehicle *v)
02466 {
02467   MarkAllViewportsDirty(
02468     min(_old_vehicle_coords.left,   v->left_coord),
02469     min(_old_vehicle_coords.top,    v->top_coord),
02470     max(_old_vehicle_coords.right,  v->right_coord) + 1,
02471     max(_old_vehicle_coords.bottom, v->bottom_coord) + 1
02472   );
02473 }
02474 
02483 void MarkSingleVehicleDirty(const Vehicle *v)
02484 {
02485   MarkAllViewportsDirty(v->left_coord, v->top_coord, v->right_coord + 1, v->bottom_coord + 1);
02486 }
02487 
02488 /* returns true if staying in the same tile */
02489 GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
02490 {
02491   static const int8 _delta_coord[16] = {
02492     -1,-1,-1, 0, 1, 1, 1, 0, /* x */
02493     -1, 0, 1, 1, 1, 0,-1,-1, /* y */
02494   };
02495 
02496   int x = v->x_pos + _delta_coord[v->direction];
02497   int y = v->y_pos + _delta_coord[v->direction + 8];
02498 
02499   GetNewVehiclePosResult gp;
02500   gp.x = x;
02501   gp.y = y;
02502   gp.old_tile = v->tile;
02503   gp.new_tile = TileVirtXY(x, y);
02504   return gp;
02505 }
02506 
02507 static const Direction _new_direction_table[] = {
02508   DIR_N , DIR_NW, DIR_W ,
02509   DIR_NE, DIR_SE, DIR_SW,
02510   DIR_E , DIR_SE, DIR_S
02511 };
02512 
02513 Direction GetDirectionTowards(const Vehicle* v, int x, int y)
02514 {
02515   Direction dir;
02516   DirDiff dirdiff;
02517   int i = 0;
02518 
02519   if (y >= v->y_pos) {
02520     if (y != v->y_pos) i+=3;
02521     i+=3;
02522   }
02523 
02524   if (x >= v->x_pos) {
02525     if (x != v->x_pos) i++;
02526     i++;
02527   }
02528 
02529   dir = v->direction;
02530 
02531   dirdiff = DirDifference(_new_direction_table[i], dir);
02532   if (dirdiff == DIRDIFF_SAME) return dir;
02533   return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
02534 }
02535 
02536 Trackdir GetVehicleTrackdir(const Vehicle* v)
02537 {
02538   if (v->vehstatus & VS_CRASHED) return INVALID_TRACKDIR;
02539 
02540   switch (v->type) {
02541     case VEH_TRAIN:
02542       if (v->u.rail.track == TRACK_BIT_DEPOT) // We'll assume the train is facing outwards
02543         return DiagdirToDiagTrackdir(GetRailDepotDirection(v->tile)); // Train in depot
02544 
02545       if (v->u.rail.track == TRACK_BIT_WORMHOLE) // train in tunnel, so just use his direction and assume a diagonal track
02546         return DiagdirToDiagTrackdir(DirToDiagDir(v->direction));
02547 
02548       return TrackDirectionToTrackdir(FindFirstTrack(v->u.rail.track), v->direction);
02549 
02550     case VEH_SHIP:
02551       if (v->IsInDepot())
02552         // We'll assume the ship is facing outwards
02553         return DiagdirToDiagTrackdir(GetShipDepotDirection(v->tile));
02554 
02555       return TrackDirectionToTrackdir(FindFirstTrack(v->u.ship.state), v->direction);
02556 
02557     case VEH_ROAD:
02558       if (v->IsInDepot()) // We'll assume the road vehicle is facing outwards
02559         return DiagdirToDiagTrackdir(GetRoadDepotDirection(v->tile));
02560 
02561       if (IsStandardRoadStopTile(v->tile)) // We'll assume the road vehicle is facing outwards
02562         return DiagdirToDiagTrackdir(GetRoadStopDir(v->tile)); // Road vehicle in a station
02563 
02564       if (IsDriveThroughStopTile(v->tile)) return DiagdirToDiagTrackdir(DirToDiagDir(v->direction));
02565 
02566       /* If vehicle's state is a valid track direction (vehicle is not turning around) return it */
02567       if (!IsReversingRoadTrackdir((Trackdir)v->u.road.state)) return (Trackdir)v->u.road.state;
02568 
02569       /* Vehicle is turning around, get the direction from vehicle's direction */
02570       return DiagdirToDiagTrackdir(DirToDiagDir(v->direction));
02571 
02572     /* case VEH_AIRCRAFT: case VEH_SPECIAL: case VEH_DISASTER: */
02573     default: return INVALID_TRACKDIR;
02574   }
02575 }
02576 
02581 uint32 VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
02582 {
02583   return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y);
02584 }
02585 
02586 UnitID GetFreeUnitNumber(VehicleType type)
02587 {
02588   UnitID unit, max = 0;
02589   const Vehicle *u;
02590   static bool *cache = NULL;
02591   static UnitID gmax = 0;
02592 
02593   switch (type) {
02594     case VEH_TRAIN:    max = _patches.max_trains; break;
02595     case VEH_ROAD:     max = _patches.max_roadveh; break;
02596     case VEH_SHIP:     max = _patches.max_ships; break;
02597     case VEH_AIRCRAFT: max = _patches.max_aircraft; break;
02598     default: NOT_REACHED();
02599   }
02600 
02601   if (max == 0) {
02602     /* we can't build any of this kind of vehicle, so we just return 1 instead of looking for a free number
02603      * a max of 0 will cause the following code to write to a NULL pointer
02604      * We know that 1 is bigger than the max allowed vehicle number, so it's the same as returning something, that is too big
02605      */
02606     return 1;
02607   }
02608 
02609   if (max > gmax) {
02610     gmax = max;
02611     free(cache);
02612     cache = MallocT<bool>(max + 1);
02613   }
02614 
02615   /* Clear the cache */
02616   memset(cache, 0, (max + 1) * sizeof(*cache));
02617 
02618   /* Fill the cache */
02619   FOR_ALL_VEHICLES(u) {
02620     if (u->type == type && u->owner == _current_player && u->unitnumber != 0 && u->unitnumber <= max)
02621       cache[u->unitnumber] = true;
02622   }
02623 
02624   /* Find the first unused unit number */
02625   for (unit = 1; unit <= max; unit++) {
02626     if (!cache[unit]) break;
02627   }
02628 
02629   return unit;
02630 }
02631 
02632 
02641 bool CanBuildVehicleInfrastructure(VehicleType type)
02642 {
02643   assert(IsPlayerBuildableVehicleType(type));
02644 
02645   if (!IsValidPlayer(_current_player)) return false;
02646   if (_patches.always_build_infrastructure) return true;
02647 
02648   UnitID max;
02649   switch (type) {
02650     case VEH_TRAIN:    max = _patches.max_trains; break;
02651     case VEH_ROAD:     max = _patches.max_roadveh; break;
02652     case VEH_SHIP:     max = _patches.max_ships; break;
02653     case VEH_AIRCRAFT: max = _patches.max_aircraft; break;
02654     default: NOT_REACHED();
02655   }
02656 
02657   /* We can build vehicle infrastructure when we may build the vehicle type */
02658   if (max > 0) {
02659 
02660     /* Can we actually build the vehicle type? */
02661     EngineID e;
02662     FOR_ALL_ENGINEIDS_OF_TYPE(e, type) {
02663       if (HasBit(GetEngine(e)->player_avail, _local_player)) return true;
02664     }
02665     return false;
02666   }
02667 
02668   /* We should be able to build infrastructure when we have the actual vehicle type */
02669   const Vehicle *v;
02670   FOR_ALL_VEHICLES(v) {
02671     if (v->owner == _local_player && v->type == type) return true;
02672   }
02673 
02674   return false;
02675 }
02676 
02677 
02678 const Livery *GetEngineLivery(EngineID engine_type, PlayerID player, EngineID parent_engine_type, const Vehicle *v)
02679 {
02680   const Player *p = GetPlayer(player);
02681   LiveryScheme scheme = LS_DEFAULT;
02682   CargoID cargo_type = v == NULL ? (CargoID)CT_INVALID : v->cargo_type;
02683 
02684   /* The default livery is always available for use, but its in_use flag determines
02685    * whether any _other_ liveries are in use. */
02686   if (p->livery[LS_DEFAULT].in_use && (_patches.liveries == 2 || (_patches.liveries == 1 && player == _local_player))) {
02687     /* Determine the livery scheme to use */
02688     switch (GetEngine(engine_type)->type) {
02689       default: NOT_REACHED();
02690       case VEH_TRAIN: {
02691         const RailVehicleInfo *rvi = RailVehInfo(engine_type);
02692 
02693         if (cargo_type == CT_INVALID) cargo_type = rvi->cargo_type;
02694         if (rvi->railveh_type == RAILVEH_WAGON) {
02695           if (!GetCargo(cargo_type)->is_freight) {
02696             if (parent_engine_type == INVALID_ENGINE) {
02697               scheme = LS_PASSENGER_WAGON_STEAM;
02698             } else {
02699               switch (RailVehInfo(parent_engine_type)->engclass) {
02700                 default: NOT_REACHED();
02701                 case EC_STEAM:    scheme = LS_PASSENGER_WAGON_STEAM;    break;
02702                 case EC_DIESEL:   scheme = LS_PASSENGER_WAGON_DIESEL;   break;
02703                 case EC_ELECTRIC: scheme = LS_PASSENGER_WAGON_ELECTRIC; break;
02704                 case EC_MONORAIL: scheme = LS_PASSENGER_WAGON_MONORAIL; break;
02705                 case EC_MAGLEV:   scheme = LS_PASSENGER_WAGON_MAGLEV;   break;
02706               }
02707             }
02708           } else {
02709             scheme = LS_FREIGHT_WAGON;
02710           }
02711         } else {
02712           bool is_mu = HasBit(EngInfo(engine_type)->misc_flags, EF_RAIL_IS_MU);
02713 
02714           switch (rvi->engclass) {
02715             default: NOT_REACHED();
02716             case EC_STEAM:    scheme = LS_STEAM; break;
02717             case EC_DIESEL:   scheme = is_mu ? LS_DMU : LS_DIESEL;   break;
02718             case EC_ELECTRIC: scheme = is_mu ? LS_EMU : LS_ELECTRIC; break;
02719             case EC_MONORAIL: scheme = LS_MONORAIL; break;
02720             case EC_MAGLEV:   scheme = LS_MAGLEV; break;
02721           }
02722         }
02723         break;
02724       }
02725 
02726       case VEH_ROAD: {
02727         const RoadVehicleInfo *rvi = RoadVehInfo(engine_type);
02728         if (cargo_type == CT_INVALID) cargo_type = rvi->cargo_type;
02729         if (HasBit(EngInfo(engine_type)->misc_flags, EF_ROAD_TRAM)) {
02730           /* Tram */
02731           scheme = IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM;
02732         } else {
02733           /* Bus or truck */
02734           scheme = IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_BUS : LS_TRUCK;
02735         }
02736         break;
02737       }
02738 
02739       case VEH_SHIP: {
02740         const ShipVehicleInfo *svi = ShipVehInfo(engine_type);
02741         if (cargo_type == CT_INVALID) cargo_type = svi->cargo_type;
02742         scheme = IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP;
02743         break;
02744       }
02745 
02746       case VEH_AIRCRAFT: {
02747         const AircraftVehicleInfo *avi = AircraftVehInfo(engine_type);
02748         if (cargo_type == CT_INVALID) cargo_type = CT_PASSENGERS;
02749         switch (avi->subtype) {
02750           case AIR_HELI: scheme = LS_HELICOPTER; break;
02751           case AIR_CTOL: scheme = LS_SMALL_PLANE; break;
02752           case AIR_CTOL | AIR_FAST: scheme = LS_LARGE_PLANE; break;
02753         }
02754         break;
02755       }
02756     }
02757 
02758     /* Switch back to the default scheme if the resolved scheme is not in use */
02759     if (!p->livery[scheme].in_use) scheme = LS_DEFAULT;
02760   }
02761 
02762   return &p->livery[scheme];
02763 }
02764 
02765 
02766 static SpriteID GetEngineColourMap(EngineID engine_type, PlayerID player, EngineID parent_engine_type, const Vehicle *v)
02767 {
02768   SpriteID map = (v != NULL) ? v->colormap : PAL_NONE;
02769 
02770   /* Return cached value if any */
02771   if (map != PAL_NONE) return map;
02772 
02773   /* Check if we should use the colour map callback */
02774   if (HasBit(EngInfo(engine_type)->callbackmask, CBM_VEHICLE_COLOUR_REMAP)) {
02775     uint16 callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v);
02776     /* A return value of 0xC000 is stated to "use the default two-color
02777      * maps" which happens to be the failure action too... */
02778     if (callback != CALLBACK_FAILED && callback != 0xC000) {
02779       map = GB(callback, 0, 14);
02780       /* If bit 14 is set, then the company colours are applied to the
02781        * map else it's returned as-is. */
02782       if (!HasBit(callback, 14)) {
02783         /* Update cache */
02784         if (v != NULL) ((Vehicle*)v)->colormap = map;
02785         return map;
02786       }
02787     }
02788   }
02789 
02790   bool twocc = HasBit(EngInfo(engine_type)->misc_flags, EF_USES_2CC);
02791 
02792   if (map == PAL_NONE) map = twocc ? (SpriteID)SPR_2CCMAP_BASE : (SpriteID)PALETTE_RECOLOR_START;
02793 
02794   const Livery *livery = GetEngineLivery(engine_type, player, parent_engine_type, v);
02795 
02796   map += livery->colour1;
02797   if (twocc) map += livery->colour2 * 16;
02798 
02799   /* Update cache */
02800   if (v != NULL) ((Vehicle*)v)->colormap = map;
02801   return map;
02802 }
02803 
02804 SpriteID GetEnginePalette(EngineID engine_type, PlayerID player)
02805 {
02806   return GetEngineColourMap(engine_type, player, INVALID_ENGINE, NULL);
02807 }
02808 
02809 SpriteID GetVehiclePalette(const Vehicle *v)
02810 {
02811   if (v->type == VEH_TRAIN) {
02812     return GetEngineColourMap(
02813       (v->u.rail.first_engine != INVALID_ENGINE && (UsesWagonOverride(v) || (IsArticulatedPart(v) && RailVehInfo(v->engine_type)->railveh_type != RAILVEH_WAGON))) ?
02814         v->u.rail.first_engine : v->engine_type,
02815       v->owner, v->u.rail.first_engine, v);
02816   }
02817 
02818   return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
02819 }
02820 
02821 static uint8  _cargo_days;
02822 static uint16 _cargo_source;
02823 static uint32 _cargo_source_xy;
02824 static uint16 _cargo_count;
02825 static uint16 _cargo_paid_for;
02826 static Money  _cargo_feeder_share;
02827 static uint32 _cargo_loaded_at_xy;
02828 
02834 const SaveLoad *GetVehicleDescription(VehicleType vt)
02835 {
02837 static const SaveLoad _common_veh_desc[] = {
02838       SLE_VAR(Vehicle, subtype,              SLE_UINT8),
02839 
02840       SLE_REF(Vehicle, next,                 REF_VEHICLE_OLD),
02841   SLE_CONDVAR(Vehicle, name,                 SLE_NAME,                    0, 83),
02842   SLE_CONDSTR(Vehicle, name,                 SLE_STR, 0,                 84, SL_MAX_VERSION),
02843   SLE_CONDVAR(Vehicle, unitnumber,           SLE_FILE_U8  | SLE_VAR_U16,  0, 7),
02844   SLE_CONDVAR(Vehicle, unitnumber,           SLE_UINT16,                  8, SL_MAX_VERSION),
02845       SLE_VAR(Vehicle, owner,                SLE_UINT8),
02846   SLE_CONDVAR(Vehicle, tile,                 SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
02847   SLE_CONDVAR(Vehicle, tile,                 SLE_UINT32,                  6, SL_MAX_VERSION),
02848   SLE_CONDVAR(Vehicle, dest_tile,            SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
02849   SLE_CONDVAR(Vehicle, dest_tile,            SLE_UINT32,                  6, SL_MAX_VERSION),
02850 
02851   SLE_CONDVAR(Vehicle, x_pos,                SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
02852   SLE_CONDVAR(Vehicle, x_pos,                SLE_UINT32,                  6, SL_MAX_VERSION),
02853   SLE_CONDVAR(Vehicle, y_pos,                SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
02854   SLE_CONDVAR(Vehicle, y_pos,                SLE_UINT32,                  6, SL_MAX_VERSION),
02855       SLE_VAR(Vehicle, z_pos,                SLE_UINT8),
02856       SLE_VAR(Vehicle, direction,            SLE_UINT8),
02857 
02858   SLE_CONDNULL(2,                                                         0, 57),
02859       SLE_VAR(Vehicle, spritenum,            SLE_UINT8),
02860   SLE_CONDNULL(5,                                                         0, 57),
02861       SLE_VAR(Vehicle, engine_type,          SLE_UINT16),
02862 
02863       SLE_VAR(Vehicle, max_speed,            SLE_UINT16),
02864       SLE_VAR(Vehicle, cur_speed,            SLE_UINT16),
02865       SLE_VAR(Vehicle, subspeed,             SLE_UINT8),
02866       SLE_VAR(Vehicle, acceleration,         SLE_UINT8),
02867       SLE_VAR(Vehicle, progress,             SLE_UINT8),
02868 
02869       SLE_VAR(Vehicle, vehstatus,            SLE_UINT8),
02870   SLE_CONDVAR(Vehicle, last_station_visited, SLE_FILE_U8  | SLE_VAR_U16,  0, 4),
02871   SLE_CONDVAR(Vehicle, last_station_visited, SLE_UINT16,                  5, SL_MAX_VERSION),
02872 
02873        SLE_VAR(Vehicle, cargo_type,           SLE_UINT8),
02874    SLE_CONDVAR(Vehicle, cargo_subtype,        SLE_UINT8,                  35, SL_MAX_VERSION),
02875   SLEG_CONDVAR(         _cargo_days,          SLE_UINT8,                   0, 67),
02876   SLEG_CONDVAR(         _cargo_source,        SLE_FILE_U8  | SLE_VAR_U16,  0, 6),
02877   SLEG_CONDVAR(         _cargo_source,        SLE_UINT16,                  7, 67),
02878   SLEG_CONDVAR(         _cargo_source_xy,     SLE_UINT32,                 44, 67),
02879        SLE_VAR(Vehicle, cargo_cap,            SLE_UINT16),
02880   SLEG_CONDVAR(         _cargo_count,         SLE_UINT16,                  0, 67),
02881    SLE_CONDLST(Vehicle, cargo,                REF_CARGO_PACKET,           68, SL_MAX_VERSION),
02882 
02883       SLE_VAR(Vehicle, day_counter,          SLE_UINT8),
02884       SLE_VAR(Vehicle, tick_counter,         SLE_UINT8),
02885   SLE_CONDVAR(Vehicle, running_ticks,        SLE_UINT8,                   88, SL_MAX_VERSION),
02886 
02887       SLE_VAR(Vehicle, cur_order_index,      SLE_UINT8),
02888       SLE_VAR(Vehicle, num_orders,           SLE_UINT8),
02889 
02890   /* This next line is for version 4 and prior compatibility.. it temporarily reads
02891       type and flags (which were both 4 bits) into type. Later on this is
02892       converted correctly */
02893   SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, type), SLE_UINT8,                 0, 4),
02894   SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest), SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
02895 
02896   /* Orders for version 5 and on */
02897   SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, type),  SLE_UINT8,  5, SL_MAX_VERSION),
02898   SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, flags), SLE_UINT8,  5, SL_MAX_VERSION),
02899   SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest),  SLE_UINT16, 5, SL_MAX_VERSION),
02900 
02901   /* Refit in current order */
02902   SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, refit_cargo),    SLE_UINT8, 36, SL_MAX_VERSION),
02903   SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, refit_subtype),  SLE_UINT8, 36, SL_MAX_VERSION),
02904 
02905   /* Timetable in current order */
02906   SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, wait_time),      SLE_UINT16, 67, SL_MAX_VERSION),
02907   SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, travel_time),    SLE_UINT16, 67, SL_MAX_VERSION),
02908 
02909       SLE_REF(Vehicle, orders,               REF_ORDER),
02910 
02911   SLE_CONDVAR(Vehicle, age,                  SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
02912   SLE_CONDVAR(Vehicle, age,                  SLE_INT32,                  31, SL_MAX_VERSION),
02913   SLE_CONDVAR(Vehicle, max_age,              SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
02914   SLE_CONDVAR(Vehicle, max_age,              SLE_INT32,                  31, SL_MAX_VERSION),
02915   SLE_CONDVAR(Vehicle, date_of_last_service, SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
02916   SLE_CONDVAR(Vehicle, date_of_last_service, SLE_INT32,                  31, SL_MAX_VERSION),
02917   SLE_CONDVAR(Vehicle, service_interval,     SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
02918   SLE_CONDVAR(Vehicle, service_interval,     SLE_INT32,                  31, SL_MAX_VERSION),
02919       SLE_VAR(Vehicle, reliability,          SLE_UINT16),
02920       SLE_VAR(Vehicle, reliability_spd_dec,  SLE_UINT16),
02921       SLE_VAR(Vehicle, breakdown_ctr,        SLE_UINT8),
02922       SLE_VAR(Vehicle, breakdown_delay,      SLE_UINT8),
02923       SLE_VAR(Vehicle, breakdowns_since_last_service, SLE_UINT8),
02924       SLE_VAR(Vehicle, breakdown_chance,     SLE_UINT8),
02925   SLE_CONDVAR(Vehicle, build_year,           SLE_FILE_U8 | SLE_VAR_I32,  0, 30),
02926   SLE_CONDVAR(Vehicle, build_year,           SLE_INT32,                 31, SL_MAX_VERSION),
02927 
02928        SLE_VAR(Vehicle, load_unload_time_rem, SLE_UINT16),
02929   SLEG_CONDVAR(         _cargo_paid_for,      SLE_UINT16,                45, SL_MAX_VERSION),
02930    SLE_CONDVAR(Vehicle, vehicle_flags,        SLE_UINT8,                 40, SL_MAX_VERSION),
02931 
02932    SLE_CONDVAR(Vehicle, profit_this_year,     SLE_FILE_I32 | SLE_VAR_I64, 0, 64),
02933    SLE_CONDVAR(Vehicle, profit_this_year,     SLE_INT64,                 65, SL_MAX_VERSION),
02934    SLE_CONDVAR(Vehicle, profit_last_year,     SLE_FILE_I32 | SLE_VAR_I64, 0, 64),
02935    SLE_CONDVAR(Vehicle, profit_last_year,     SLE_INT64,                 65, SL_MAX_VERSION),
02936   SLEG_CONDVAR(         _cargo_feeder_share,  SLE_FILE_I32 | SLE_VAR_I64,51, 64),
02937   SLEG_CONDVAR(         _cargo_feeder_share,  SLE_INT64,                 65, 67),
02938   SLEG_CONDVAR(         _cargo_loaded_at_xy,  SLE_UINT32,                51, 67),
02939    SLE_CONDVAR(Vehicle, value,                SLE_FILE_I32 | SLE_VAR_I64, 0, 64),
02940    SLE_CONDVAR(Vehicle, value,                SLE_INT64,                 65, SL_MAX_VERSION),
02941 
02942    SLE_CONDVAR(Vehicle, random_bits,          SLE_UINT8,                 2, SL_MAX_VERSION),
02943    SLE_CONDVAR(Vehicle, waiting_triggers,     SLE_UINT8,                 2, SL_MAX_VERSION),
02944 
02945    SLE_CONDREF(Vehicle, next_shared,        REF_VEHICLE,                 2, SL_MAX_VERSION),
02946    SLE_CONDREF(Vehicle, prev_shared,        REF_VEHICLE,                 2, SL_MAX_VERSION),
02947 
02948   SLE_CONDVAR(Vehicle, group_id,             SLE_UINT16,                60, SL_MAX_VERSION),
02949 
02950   SLE_CONDVAR(Vehicle, current_order_time,   SLE_UINT32,                67, SL_MAX_VERSION),
02951   SLE_CONDVAR(Vehicle, lateness_counter,     SLE_INT32,                 67, SL_MAX_VERSION),
02952 
02953   /* reserve extra space in savegame here. (currently 10 bytes) */
02954   SLE_CONDNULL(10,                                                       2, SL_MAX_VERSION),
02955 
02956   SLE_END()
02957 };
02958 
02959 
02960 static const SaveLoad _train_desc[] = {
02961   SLE_WRITEBYTE(Vehicle, type, VEH_TRAIN),
02962   SLE_VEH_INCLUDEX(),
02963       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, crash_anim_pos),         SLE_UINT16),
02964       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, force_proceed),          SLE_UINT8),
02965       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, railtype),               SLE_UINT8),
02966       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, track),                  SLE_UINT8),
02967 
02968   SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRail, flags),                  SLE_UINT8,  2, SL_MAX_VERSION),
02969   SLE_CONDNULL(2, 2, 59),
02970 
02971   SLE_CONDNULL(2, 2, 19),
02972   /* reserve extra space in savegame here. (currently 11 bytes) */
02973   SLE_CONDNULL(11, 2, SL_MAX_VERSION),
02974 
02975   SLE_END()
02976 };
02977 
02978 static const SaveLoad _roadveh_desc[] = {
02979   SLE_WRITEBYTE(Vehicle, type, VEH_ROAD),
02980   SLE_VEH_INCLUDEX(),
02981       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, state),          SLE_UINT8),
02982       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, frame),          SLE_UINT8),
02983       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, blocked_ctr),    SLE_UINT16),
02984       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, overtaking),     SLE_UINT8),
02985       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, overtaking_ctr), SLE_UINT8),
02986       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, crashed_ctr),    SLE_UINT16),
02987       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, reverse_ctr),    SLE_UINT8),
02988 
02989   SLE_CONDREFX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, slot),     REF_ROADSTOPS, 6, SL_MAX_VERSION),
02990   SLE_CONDNULL(1,                                                                     6, SL_MAX_VERSION),
02991   SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleRoad, slot_age), SLE_UINT8,     6, SL_MAX_VERSION),
02992   /* reserve extra space in savegame here. (currently 16 bytes) */
02993   SLE_CONDNULL(16,                                                                    2, SL_MAX_VERSION),
02994 
02995   SLE_END()
02996 };
02997 
02998 static const SaveLoad _ship_desc[] = {
02999   SLE_WRITEBYTE(Vehicle, type, VEH_SHIP),
03000   SLE_VEH_INCLUDEX(),
03001   SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleShip, state), SLE_UINT8),
03002 
03003   /* reserve extra space in savegame here. (currently 16 bytes) */
03004   SLE_CONDNULL(16, 2, SL_MAX_VERSION),
03005 
03006   SLE_END()
03007 };
03008 
03009 static const SaveLoad _aircraft_desc[] = {
03010   SLE_WRITEBYTE(Vehicle, type, VEH_AIRCRAFT),
03011   SLE_VEH_INCLUDEX(),
03012       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, crashed_counter), SLE_UINT16),
03013       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, pos),             SLE_UINT8),
03014 
03015   SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, targetairport),   SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
03016   SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, targetairport),   SLE_UINT16,                5, SL_MAX_VERSION),
03017 
03018       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, state),           SLE_UINT8),
03019 
03020   SLE_CONDVARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleAir, previous_pos),    SLE_UINT8,                 2, SL_MAX_VERSION),
03021 
03022   /* reserve extra space in savegame here. (currently 15 bytes) */
03023   SLE_CONDNULL(15,                                                                                      2, SL_MAX_VERSION),
03024 
03025   SLE_END()
03026 };
03027 
03028 static const SaveLoad _special_desc[] = {
03029   SLE_WRITEBYTE(Vehicle, type, VEH_SPECIAL),
03030 
03031       SLE_VAR(Vehicle, subtype,       SLE_UINT8),
03032 
03033   SLE_CONDVAR(Vehicle, tile,          SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
03034   SLE_CONDVAR(Vehicle, tile,          SLE_UINT32,                 6, SL_MAX_VERSION),
03035 
03036   SLE_CONDVAR(Vehicle, x_pos,         SLE_FILE_I16 | SLE_VAR_I32, 0, 5),
03037   SLE_CONDVAR(Vehicle, x_pos,         SLE_INT32,                  6, SL_MAX_VERSION),
03038   SLE_CONDVAR(Vehicle, y_pos,         SLE_FILE_I16 | SLE_VAR_I32, 0, 5),
03039   SLE_CONDVAR(Vehicle, y_pos,         SLE_INT32,                  6, SL_MAX_VERSION),
03040       SLE_VAR(Vehicle, z_pos,         SLE_UINT8),
03041 
03042       SLE_VAR(Vehicle, cur_image,     SLE_UINT16),
03043   SLE_CONDNULL(5,                                                 0, 57),
03044       SLE_VAR(Vehicle, progress,      SLE_UINT8),
03045       SLE_VAR(Vehicle, vehstatus,     SLE_UINT8),
03046 
03047       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleSpecial, animation_state),    SLE_UINT16),
03048       SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleSpecial, animation_substate), SLE_UINT8),
03049 
03050   SLE_CONDVAR(Vehicle, spritenum,     SLE_UINT8, 2, SL_MAX_VERSION),
03051 
03052   /* reserve extra space in savegame here. (currently 15 bytes) */
03053   SLE_CONDNULL(15, 2, SL_MAX_VERSION),
03054 
03055   SLE_END()
03056 };
03057 
03058 static const SaveLoad _disaster_desc[] = {
03059   SLE_WRITEBYTE(Vehicle, type, VEH_DISASTER),
03060 
03061       SLE_REF(Vehicle, next,          REF_VEHICLE_OLD),
03062 
03063       SLE_VAR(Vehicle, subtype,       SLE_UINT8),
03064   SLE_CONDVAR(Vehicle, tile,          SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
03065   SLE_CONDVAR(Vehicle, tile,          SLE_UINT32,                  6, SL_MAX_VERSION),
03066   SLE_CONDVAR(Vehicle, dest_tile,     SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
03067   SLE_CONDVAR(Vehicle, dest_tile,     SLE_UINT32,                  6, SL_MAX_VERSION),
03068 
03069   SLE_CONDVAR(Vehicle, x_pos,         SLE_FILE_I16 | SLE_VAR_I32,  0, 5),
03070   SLE_CONDVAR(Vehicle, x_pos,         SLE_INT32,                   6, SL_MAX_VERSION),
03071   SLE_CONDVAR(Vehicle, y_pos,         SLE_FILE_I16 | SLE_VAR_I32,  0, 5),
03072   SLE_CONDVAR(Vehicle, y_pos,         SLE_INT32,                   6, SL_MAX_VERSION),
03073       SLE_VAR(Vehicle, z_pos,         SLE_UINT8),
03074       SLE_VAR(Vehicle, direction,     SLE_UINT8),
03075 
03076   SLE_CONDNULL(5,                                                  0, 57),
03077       SLE_VAR(Vehicle, owner,         SLE_UINT8),
03078       SLE_VAR(Vehicle, vehstatus,     SLE_UINT8),
03079   SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest), SLE_FILE_U8 | SLE_VAR_U16, 0, 4),
03080   SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, dest), SLE_UINT16,                5, SL_MAX_VERSION),
03081 
03082       SLE_VAR(Vehicle, cur_image,     SLE_UINT16),
03083   SLE_CONDVAR(Vehicle, age,           SLE_FILE_U16 | SLE_VAR_I32,  0, 30),
03084   SLE_CONDVAR(Vehicle, age,           SLE_INT32,                  31, SL_MAX_VERSION),
03085       SLE_VAR(Vehicle, tick_counter,  SLE_UINT8),
03086 
03087      SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleDisaster, image_override),           SLE_UINT16),
03088      SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleDisaster, big_ufo_destroyer_target), SLE_UINT16),
03089 
03090   /* reserve extra space in savegame here. (currently 16 bytes) */
03091   SLE_CONDNULL(16,                                                 2, SL_MAX_VERSION),
03092 
03093   SLE_END()
03094 };
03095 
03096 
03097 static const SaveLoad *_veh_descs[] = {
03098   _train_desc,
03099   _roadveh_desc,
03100   _ship_desc,
03101   _aircraft_desc,
03102   _special_desc,
03103   _disaster_desc,
03104   _common_veh_desc,
03105 };
03106 
03107   return _veh_descs[vt];
03108 }
03109 
03111 static void Save_VEHS()
03112 {
03113   Vehicle *v;
03114   /* Write the vehicles */
03115   FOR_ALL_VEHICLES(v) {
03116     SlSetArrayIndex(v->index);
03117     SlObject(v, GetVehicleDescription(v->type));
03118   }
03119 }
03120 
03122 static void Load_VEHS()
03123 {
03124   int index;
03125   Vehicle *v;
03126 
03127   _cargo_count = 0;
03128 
03129   while ((index = SlIterateArray()) != -1) {
03130     Vehicle *v;
03131     VehicleType vtype = (VehicleType)SlReadByte();
03132 
03133     switch (vtype) {
03134       case VEH_TRAIN:    v = new (index) Train();           break;
03135       case VEH_ROAD:     v = new (index) RoadVehicle();     break;
03136       case VEH_SHIP:     v = new (index) Ship();            break;
03137       case VEH_AIRCRAFT: v = new (index) Aircraft();        break;
03138       case VEH_SPECIAL:  v = new (index) SpecialVehicle();  break;
03139       case VEH_DISASTER: v = new (index) DisasterVehicle(); break;
03140       case VEH_INVALID:  v = new (index) InvalidVehicle();  break;
03141       default: NOT_REACHED();
03142     }
03143 
03144     SlObject(v, GetVehicleDescription(vtype));
03145 
03146     if (_cargo_count != 0 && IsPlayerBuildableVehicleType(v)) {
03147       /* Don't construct the packet with station here, because that'll fail with old savegames */
03148       CargoPacket *cp = new CargoPacket();
03149       cp->source          = _cargo_source;
03150       cp->source_xy       = _cargo_source_xy;
03151       cp->count           = _cargo_count;
03152       cp->days_in_transit = _cargo_days;
03153       cp->feeder_share    = _cargo_feeder_share;
03154       cp->loaded_at_xy    = _cargo_loaded_at_xy;
03155       v->cargo.Append(cp);
03156     }
03157 
03158     /* Old savegames used 'last_station_visited = 0xFF' */
03159     if (CheckSavegameVersion(5) && v->last_station_visited == 0xFF)
03160       v->last_station_visited = INVALID_STATION;
03161 
03162     if (CheckSavegameVersion(5)) {
03163       /* Convert the current_order.type (which is a mix of type and flags, because
03164        *  in those versions, they both were 4 bits big) to type and flags */
03165       v->current_order.flags = (v->current_order.type & 0xF0) >> 4;
03166       v->current_order.type.m_val &= 0x0F;
03167     }
03168 
03169     /* Advanced vehicle lists got added */
03170     if (CheckSavegameVersion(60)) v->group_id = DEFAULT_GROUP;
03171   }
03172 
03173   /* Check for shared order-lists (we now use pointers for that) */
03174   if (CheckSavegameVersionOldStyle(5, 2)) {
03175     FOR_ALL_VEHICLES(v) {
03176       Vehicle *u;
03177 
03178       FOR_ALL_VEHICLES_FROM(u, v->index + 1) {
03179         /* If a vehicle has the same orders, add the link to eachother
03180          *  in both vehicles */
03181         if (v->orders == u->orders) {
03182           v->next_shared = u;
03183           u->prev_shared = v;
03184           break;
03185         }
03186       }
03187     }
03188   }
03189 }
03190 
03191 extern const ChunkHandler _veh_chunk_handlers[] = {
03192   { 'VEHS', Save_VEHS, Load_VEHS, CH_SPARSE_ARRAY | CH_LAST},
03193 };
03194 
03195 void Vehicle::BeginLoading()
03196 {
03197   assert(IsTileType(tile, MP_STATION) || type == VEH_SHIP);
03198 
03199   if (this->current_order.type == OT_GOTO_STATION &&
03200       this->current_order.dest == this->last_station_visited) {
03201     /* Arriving at the ordered station.
03202      * Keep the load/unload flags, as we (obviously) still need them. */
03203     this->current_order.flags &= OFB_FULL_LOAD | OFB_UNLOAD | OFB_TRANSFER;
03204 
03205     /* Furthermore add the Non Stop flag to mark that this station
03206      * is the actual destination of the vehicle, which is (for example)
03207      * necessary to be known for HandleTrainLoading to determine
03208      * whether the train is lost or not; not marking a train lost
03209      * that arrives at random stations is bad. */
03210     this->current_order.flags |= OFB_NON_STOP;
03211     UpdateVehicleTimetable(this, true);
03212   } else {
03213     /* This is just an unordered intermediate stop */
03214     this->current_order.flags = 0;
03215   }
03216 
03217   current_order.type = OT_LOADING;
03218   GetStation(this->last_station_visited)->loading_vehicles.push_back(this);
03219 
03220   VehiclePayment(this);
03221 
03222   InvalidateWindow(this->GetVehicleListWindowClass(), this->owner);
03223   InvalidateWindowWidget(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
03224   InvalidateWindow(WC_VEHICLE_DETAILS, this->index);
03225   InvalidateWindow(WC_STATION_VIEW, this->last_station_visited);
03226 
03227   GetStation(this->last_station_visited)->MarkTilesDirty(true);
03228   this->MarkDirty();
03229 }
03230 
03231 void Vehicle::LeaveStation()
03232 {
03233   assert(current_order.type == OT_LOADING);
03234 
03235   /* Only update the timetable if the vehicle was supposed to stop here. */
03236   if (current_order.flags & OFB_NON_STOP) UpdateVehicleTimetable(this, false);
03237 
03238   current_order.type = OT_LEAVESTATION;
03239   current_order.flags = 0;
03240   GetStation(this->last_station_visited)->loading_vehicles.remove(this);
03241 
03242   HideFillingPercent(&this->fill_percent_te_id);
03243 }
03244 
03245 
03246 void Vehicle::HandleLoading(bool mode)
03247 {
03248   switch (this->current_order.type) {
03249     case OT_LOADING: {
03250       uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0);
03251 
03252       /* Not the first call for this tick, or still loading */
03253       if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) ||
03254           (_patches.timetabling && this->current_order_time < wait_time)) return;
03255 
03256       this->PlayLeaveStationSound();
03257 
03258       Order b = this->current_order;
03259       this->LeaveStation();
03260 
03261       /* If this was not the final order, don't remove it from the list. */
03262       if (!(b.flags & OFB_NON_STOP)) return;
03263       break;
03264     }
03265 
03266     case OT_DUMMY: break;
03267 
03268     default: return;
03269   }
03270 
03271   this->cur_order_index++;
03272   InvalidateVehicleOrder(this);
03273 }
03274 
03275 void Vehicle::SetNext(Vehicle *next)
03276 {
03277   if (this->next != NULL) {
03278     /* We had an old next vehicle. Update the first and previous pointers */
03279     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
03280       v->first = this->next;
03281     }
03282     this->next->previous = NULL;
03283   }
03284 
03285   this->next = next;
03286 
03287   if (this->next != NULL) {
03288     /* A new next vehicle. Update the first and previous pointers */
03289     if (this->next->previous != NULL) this->next->previous->next = NULL;
03290     this->next->previous = this;
03291     for (Vehicle *v = this->next; v != NULL; v = v->Next()) {
03292       v->first = this->first;
03293     }
03294   }
03295 }
03296 
03297 void SpecialVehicle::UpdateDeltaXY(Direction direction)
03298 {
03299   this->x_offs        = 0;
03300   this->y_offs        = 0;
03301   this->sprite_width  = 1;
03302   this->sprite_height = 1;
03303   this->z_height      = 1;
03304 }
03305 
03306 void StopAllVehicles()
03307 {
03308   Vehicle *v;
03309   FOR_ALL_VEHICLES(v) {
03310     /* Code ripped from CmdStartStopTrain. Can't call it, because of
03311      * ownership problems, so we'll duplicate some code, for now */
03312     v->vehstatus |= VS_STOPPED;
03313     InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
03314     InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
03315   }
03316 }

Generated on Wed Oct 1 17:03:25 2008 for openttd by  doxygen 1.5.6