train_cmd.cpp

Go to the documentation of this file.
00001 /* $Id: train_cmd.cpp 14852 2009-01-05 20:29:05Z michi_cc $ */
00002 
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "bridge_map.h"
00008 #include "debug.h"
00009 #include "tile_cmd.h"
00010 #include "landscape.h"
00011 #include "gui.h"
00012 #include "station_map.h"
00013 #include "tunnel_map.h"
00014 #include "articulated_vehicles.h"
00015 #include "command_func.h"
00016 #include "pathfind.h"
00017 #include "npf.h"
00018 #include "station_base.h"
00019 #include "news_func.h"
00020 #include "engine_func.h"
00021 #include "engine_base.h"
00022 #include "company_func.h"
00023 #include "company_base.h"
00024 #include "depot_base.h"
00025 #include "depot_func.h"
00026 #include "waypoint.h"
00027 #include "vehicle_gui.h"
00028 #include "train.h"
00029 #include "bridge.h"
00030 #include "newgrf_callbacks.h"
00031 #include "newgrf_engine.h"
00032 #include "newgrf_sound.h"
00033 #include "newgrf_text.h"
00034 #include "direction_func.h"
00035 #include "yapf/yapf.h"
00036 #include "yapf/follow_track.hpp"
00037 #include "cargotype.h"
00038 #include "group.h"
00039 #include "table/sprites.h"
00040 #include "tunnelbridge_map.h"
00041 #include "strings_func.h"
00042 #include "functions.h"
00043 #include "window_func.h"
00044 #include "date_func.h"
00045 #include "vehicle_func.h"
00046 #include "sound_func.h"
00047 #include "signal_func.h"
00048 #include "variables.h"
00049 #include "autoreplace_gui.h"
00050 #include "gfx_func.h"
00051 #include "settings_type.h"
00052 #include "order_func.h"
00053 #include "newgrf_station.h"
00054 #include "effectvehicle_func.h"
00055 #include "gamelog.h"
00056 #include "network/network.h"
00057 #include "pbs.h"
00058 
00059 #include "table/strings.h"
00060 #include "table/train_cmd.h"
00061 
00062 static Track ChooseTrainTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck);
00063 static bool TrainCheckIfLineEnds(Vehicle *v);
00064 static void TrainController(Vehicle *v, Vehicle *nomove, bool update_image);
00065 static TileIndex TrainApproachingCrossingTile(const Vehicle *v);
00066 static void CheckIfTrainNeedsService(Vehicle *v);
00067 static void CheckNextTrainTile(Vehicle *v);
00068 
00069 static const byte _vehicle_initial_x_fract[4] = {10, 8, 4,  8};
00070 static const byte _vehicle_initial_y_fract[4] = { 8, 4, 8, 10};
00071 
00072 
00080 static inline DiagDirection TrainExitDir(Direction direction, TrackBits track)
00081 {
00082   static const TrackBits state_dir_table[DIAGDIR_END] = { TRACK_BIT_RIGHT, TRACK_BIT_LOWER, TRACK_BIT_LEFT, TRACK_BIT_UPPER };
00083 
00084   DiagDirection diagdir = DirToDiagDir(direction);
00085 
00086   /* Determine the diagonal direction in which we will exit this tile */
00087   if (!HasBit(direction, 0) && track != state_dir_table[diagdir]) {
00088     diagdir = ChangeDiagDir(diagdir, DIAGDIRDIFF_90LEFT);
00089   }
00090 
00091   return diagdir;
00092 }
00093 
00094 
00099 byte FreightWagonMult(CargoID cargo)
00100 {
00101   if (!GetCargo(cargo)->is_freight) return 1;
00102   return _settings_game.vehicle.freight_trains;
00103 }
00104 
00105 
00110 void TrainPowerChanged(Vehicle *v)
00111 {
00112   uint32 total_power = 0;
00113   uint32 max_te = 0;
00114 
00115   for (const Vehicle *u = v; u != NULL; u = u->Next()) {
00116     RailType railtype = GetRailType(u->tile);
00117 
00118     /* Power is not added for articulated parts */
00119     if (!IsArticulatedPart(u)) {
00120       bool engine_has_power = HasPowerOnRail(u->u.rail.railtype, railtype);
00121 
00122       const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type);
00123 
00124       if (engine_has_power) {
00125         uint16 power = GetVehicleProperty(u, 0x0B, rvi_u->power);
00126         if (power != 0) {
00127           /* Halve power for multiheaded parts */
00128           if (IsMultiheaded(u)) power /= 2;
00129 
00130           total_power += power;
00131           /* Tractive effort in (tonnes * 1000 * 10 =) N */
00132           max_te += (u->u.rail.cached_veh_weight * 10000 * GetVehicleProperty(u, 0x1F, rvi_u->tractive_effort)) / 256;
00133         }
00134       }
00135     }
00136 
00137     if (HasBit(u->u.rail.flags, VRF_POWEREDWAGON) && HasPowerOnRail(v->u.rail.railtype, railtype)) {
00138       total_power += RailVehInfo(u->u.rail.first_engine)->pow_wag_power;
00139     }
00140   }
00141 
00142   if (v->u.rail.cached_power != total_power || v->u.rail.cached_max_te != max_te) {
00143     /* If it has no power (no catenary), stop the train */
00144     if (total_power == 0) v->vehstatus |= VS_STOPPED;
00145 
00146     v->u.rail.cached_power = total_power;
00147     v->u.rail.cached_max_te = max_te;
00148     InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
00149     InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
00150   }
00151 }
00152 
00153 
00159 static void TrainCargoChanged(Vehicle *v)
00160 {
00161   uint32 weight = 0;
00162 
00163   for (Vehicle *u = v; u != NULL; u = u->Next()) {
00164     uint32 vweight = GetCargo(u->cargo_type)->weight * u->cargo.Count() * FreightWagonMult(u->cargo_type) / 16;
00165 
00166     /* Vehicle weight is not added for articulated parts. */
00167     if (!IsArticulatedPart(u)) {
00168       /* vehicle weight is the sum of the weight of the vehicle and the weight of its cargo */
00169       vweight += GetVehicleProperty(u, 0x16, RailVehInfo(u->engine_type)->weight);
00170     }
00171 
00172     /* powered wagons have extra weight added */
00173     if (HasBit(u->u.rail.flags, VRF_POWEREDWAGON)) {
00174       vweight += RailVehInfo(u->u.rail.first_engine)->pow_wag_weight;
00175     }
00176 
00177     /* consist weight is the sum of the weight of all vehicles in the consist */
00178     weight += vweight;
00179 
00180     /* store vehicle weight in cache */
00181     u->u.rail.cached_veh_weight = vweight;
00182   }
00183 
00184   /* store consist weight in cache */
00185   v->u.rail.cached_weight = weight;
00186 
00187   /* Now update train power (tractive effort is dependent on weight) */
00188   TrainPowerChanged(v);
00189 }
00190 
00191 
00196 static void RailVehicleLengthChanged(const Vehicle *u)
00197 {
00198   /* show a warning once for each engine in whole game and once for each GRF after each game load */
00199   const Engine *engine = GetEngine(u->engine_type);
00200   uint32 grfid = engine->grffile->grfid;
00201   GRFConfig *grfconfig = GetGRFConfig(grfid);
00202   if (GamelogGRFBugReverse(grfid, engine->internal_id) || !HasBit(grfconfig->grf_bugs, GBUG_VEH_LENGTH)) {
00203     SetBit(grfconfig->grf_bugs, GBUG_VEH_LENGTH);
00204     SetDParamStr(0, grfconfig->name);
00205     SetDParam(1, u->engine_type);
00206     ShowErrorMessage(STR_NEWGRF_BROKEN_VEHICLE_LENGTH, STR_NEWGRF_BROKEN, 0, 0);
00207 
00208     /* debug output */
00209     char buffer[512];
00210 
00211     SetDParamStr(0, grfconfig->name);
00212     GetString(buffer, STR_NEWGRF_BROKEN, lastof(buffer));
00213     DEBUG(grf, 0, "%s", buffer + 3);
00214 
00215     SetDParam(1, u->engine_type);
00216     GetString(buffer, STR_NEWGRF_BROKEN_VEHICLE_LENGTH, lastof(buffer));
00217     DEBUG(grf, 0, "%s", buffer + 3);
00218 
00219     if (!_networking) _pause_game = -1;
00220   }
00221 }
00222 
00224 void CheckTrainsLengths()
00225 {
00226   const Vehicle *v;
00227 
00228   FOR_ALL_VEHICLES(v) {
00229     if (v->type == VEH_TRAIN && v->First() == v && !(v->vehstatus & VS_CRASHED)) {
00230       for (const Vehicle *u = v, *w = v->Next(); w != NULL; u = w, w = w->Next()) {
00231         if (u->u.rail.track != TRACK_BIT_DEPOT) {
00232           if ((w->u.rail.track != TRACK_BIT_DEPOT &&
00233               max(abs(u->x_pos - w->x_pos), abs(u->y_pos - w->y_pos)) != u->u.rail.cached_veh_length) ||
00234               (w->u.rail.track == TRACK_BIT_DEPOT && TicksToLeaveDepot(u) <= 0)) {
00235             SetDParam(0, v->index);
00236             SetDParam(1, v->owner);
00237             ShowErrorMessage(INVALID_STRING_ID, STR_BROKEN_VEHICLE_LENGTH, 0, 0);
00238 
00239             if (!_networking) _pause_game = -1;
00240           }
00241         }
00242       }
00243     }
00244   }
00245 }
00246 
00254 void TrainConsistChanged(Vehicle *v, bool same_length)
00255 {
00256   uint16 max_speed = UINT16_MAX;
00257 
00258   assert(v->type == VEH_TRAIN);
00259   assert(IsFrontEngine(v) || IsFreeWagon(v));
00260 
00261   const RailVehicleInfo *rvi_v = RailVehInfo(v->engine_type);
00262   EngineID first_engine = IsFrontEngine(v) ? v->engine_type : INVALID_ENGINE;
00263   v->u.rail.cached_total_length = 0;
00264   v->u.rail.compatible_railtypes = RAILTYPES_NONE;
00265 
00266   bool train_can_tilt = true;
00267 
00268   for (Vehicle *u = v; u != NULL; u = u->Next()) {
00269     const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type);
00270 
00271     /* Check the v->first cache. */
00272     assert(u->First() == v);
00273 
00274     /* update the 'first engine' */
00275     u->u.rail.first_engine = v == u ? INVALID_ENGINE : first_engine;
00276     u->u.rail.railtype = rvi_u->railtype;
00277 
00278     if (IsTrainEngine(u)) first_engine = u->engine_type;
00279 
00280     /* Set user defined data to its default value */
00281     u->u.rail.user_def_data = rvi_u->user_def_data;
00282   }
00283 
00284   for (Vehicle *u = v; u != NULL; u = u->Next()) {
00285     /* Update user defined data (must be done before other properties) */
00286     u->u.rail.user_def_data = GetVehicleProperty(u, 0x25, u->u.rail.user_def_data);
00287   }
00288 
00289   for (Vehicle *u = v; u != NULL; u = u->Next()) {
00290     const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type);
00291 
00292     if (!HasBit(EngInfo(u->engine_type)->misc_flags, EF_RAIL_TILTS)) train_can_tilt = false;
00293 
00294     /* Cache wagon override sprite group. NULL is returned if there is none */
00295     u->u.rail.cached_override = GetWagonOverrideSpriteSet(u->engine_type, u->cargo_type, u->u.rail.first_engine);
00296 
00297     /* Reset color map */
00298     u->colormap = PAL_NONE;
00299 
00300     if (rvi_u->visual_effect != 0) {
00301       u->u.rail.cached_vis_effect = rvi_u->visual_effect;
00302     } else {
00303       if (IsTrainWagon(u) || IsArticulatedPart(u)) {
00304         /* Wagons and articulated parts have no effect by default */
00305         u->u.rail.cached_vis_effect = 0x40;
00306       } else if (rvi_u->engclass == 0) {
00307         /* Steam is offset by -4 units */
00308         u->u.rail.cached_vis_effect = 4;
00309       } else {
00310         /* Diesel fumes and sparks come from the centre */
00311         u->u.rail.cached_vis_effect = 8;
00312       }
00313     }
00314 
00315     /* Check powered wagon / visual effect callback */
00316     if (HasBit(EngInfo(u->engine_type)->callbackmask, CBM_TRAIN_WAGON_POWER)) {
00317       uint16 callback = GetVehicleCallback(CBID_TRAIN_WAGON_POWER, 0, 0, u->engine_type, u);
00318 
00319       if (callback != CALLBACK_FAILED) u->u.rail.cached_vis_effect = GB(callback, 0, 8);
00320     }
00321 
00322     if (rvi_v->pow_wag_power != 0 && rvi_u->railveh_type == RAILVEH_WAGON &&
00323       UsesWagonOverride(u) && !HasBit(u->u.rail.cached_vis_effect, 7)) {
00324       /* wagon is powered */
00325       SetBit(u->u.rail.flags, VRF_POWEREDWAGON); // cache 'powered' status
00326     } else {
00327       ClrBit(u->u.rail.flags, VRF_POWEREDWAGON);
00328     }
00329 
00330     if (!IsArticulatedPart(u)) {
00331       /* Do not count powered wagons for the compatible railtypes, as wagons always
00332          have railtype normal */
00333       if (rvi_u->power > 0) {
00334         v->u.rail.compatible_railtypes |= GetRailTypeInfo(u->u.rail.railtype)->powered_railtypes;
00335       }
00336 
00337       /* Some electric engines can be allowed to run on normal rail. It happens to all
00338        * existing electric engines when elrails are disabled and then re-enabled */
00339       if (HasBit(u->u.rail.flags, VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL)) {
00340         u->u.rail.railtype = RAILTYPE_RAIL;
00341         u->u.rail.compatible_railtypes |= RAILTYPES_RAIL;
00342       }
00343 
00344       /* max speed is the minimum of the speed limits of all vehicles in the consist */
00345       if ((rvi_u->railveh_type != RAILVEH_WAGON || _settings_game.vehicle.wagon_speed_limits) && !UsesWagonOverride(u)) {
00346         uint16 speed = GetVehicleProperty(u, 0x09, rvi_u->max_speed);
00347         if (speed != 0) max_speed = min(speed, max_speed);
00348       }
00349     }
00350 
00351     if (u->cargo_type == rvi_u->cargo_type && u->cargo_subtype == 0) {
00352       /* Set cargo capacity if we've not been refitted */
00353       u->cargo_cap = GetVehicleProperty(u, 0x14, rvi_u->capacity);
00354     }
00355 
00356     /* check the vehicle length (callback) */
00357     uint16 veh_len = CALLBACK_FAILED;
00358     if (HasBit(EngInfo(u->engine_type)->callbackmask, CBM_VEHICLE_LENGTH)) {
00359       veh_len = GetVehicleCallback(CBID_VEHICLE_LENGTH, 0, 0, u->engine_type, u);
00360     }
00361     if (veh_len == CALLBACK_FAILED) veh_len = rvi_u->shorten_factor;
00362     veh_len = 8 - Clamp(veh_len, 0, u->Next() == NULL ? 7 : 5); // the clamp on vehicles not the last in chain is stricter, as too short wagons can break the 'follow next vehicle' code
00363 
00364     /* verify length hasn't changed */
00365     if (same_length && veh_len != u->u.rail.cached_veh_length) RailVehicleLengthChanged(u);
00366 
00367     /* update vehicle length? */
00368     if (!same_length) u->u.rail.cached_veh_length = veh_len;
00369 
00370     v->u.rail.cached_total_length += u->u.rail.cached_veh_length;
00371   }
00372 
00373   /* store consist weight/max speed in cache */
00374   v->u.rail.cached_max_speed = max_speed;
00375   v->u.rail.cached_tilt = train_can_tilt;
00376 
00377   /* recalculate cached weights and power too (we do this *after* the rest, so it is known which wagons are powered and need extra weight added) */
00378   TrainCargoChanged(v);
00379 
00380   if (IsFrontEngine(v)) {
00381     UpdateTrainAcceleration(v);
00382     InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
00383   }
00384 }
00385 
00386 enum AccelType {
00387   AM_ACCEL,
00388   AM_BRAKE
00389 };
00390 
00392 static int GetTrainAcceleration(Vehicle *v, bool mode)
00393 {
00394   static const int absolute_max_speed = UINT16_MAX;
00395   int max_speed = absolute_max_speed;
00396   int speed = v->cur_speed * 10 / 16; // km-ish/h -> mp/h
00397   int curvecount[2] = {0, 0};
00398 
00399   /*first find the curve speed limit */
00400   int numcurve = 0;
00401   int sum = 0;
00402   int pos = 0;
00403   int lastpos = -1;
00404   for (const Vehicle *u = v; u->Next() != NULL; u = u->Next(), pos++) {
00405     Direction this_dir = u->direction;
00406     Direction next_dir = u->Next()->direction;
00407 
00408     DirDiff dirdiff = DirDifference(this_dir, next_dir);
00409     if (dirdiff == DIRDIFF_SAME) continue;
00410 
00411     if (dirdiff == DIRDIFF_45LEFT) curvecount[0]++;
00412     if (dirdiff == DIRDIFF_45RIGHT) curvecount[1]++;
00413     if (dirdiff == DIRDIFF_45LEFT || dirdiff == DIRDIFF_45RIGHT) {
00414       if (lastpos != -1) {
00415         numcurve++;
00416         sum += pos - lastpos;
00417         if (pos - lastpos == 1) {
00418           max_speed = 88;
00419         }
00420       }
00421       lastpos = pos;
00422     }
00423 
00424     /*if we have a 90 degree turn, fix the speed limit to 60 */
00425     if (dirdiff == DIRDIFF_90LEFT || dirdiff == DIRDIFF_90RIGHT) {
00426       max_speed = 61;
00427     }
00428   }
00429 
00430   if ((curvecount[0] != 0 || curvecount[1] != 0) && max_speed > 88) {
00431     int total = curvecount[0] + curvecount[1];
00432 
00433     if (curvecount[0] == 1 && curvecount[1] == 1) {
00434       max_speed = absolute_max_speed;
00435     } else if (total > 1) {
00436       if (numcurve > 0) sum /= numcurve;
00437       max_speed = 232 - (13 - Clamp(sum, 1, 12)) * (13 - Clamp(sum, 1, 12));
00438     }
00439   }
00440 
00441   if (max_speed != absolute_max_speed) {
00442     /* Apply the engine's rail type curve speed advantage, if it slowed by curves */
00443     const RailtypeInfo *rti = GetRailTypeInfo(v->u.rail.railtype);
00444     max_speed += (max_speed / 2) * rti->curve_speed;
00445 
00446     if (v->u.rail.cached_tilt) {
00447       /* Apply max_speed bonus of 20% for a tilting train */
00448       max_speed += max_speed / 5;
00449     }
00450   }
00451 
00452   if (IsTileType(v->tile, MP_STATION) && IsFrontEngine(v)) {
00453     if (v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile))) {
00454       int station_length = GetStationByTile(v->tile)->GetPlatformLength(v->tile, DirToDiagDir(v->direction));
00455 
00456       int st_max_speed = 120;
00457 
00458       int delta_v = v->cur_speed / (station_length + 1);
00459       if (v->max_speed > (v->cur_speed - delta_v)) {
00460         st_max_speed = v->cur_speed - (delta_v / 10);
00461       }
00462 
00463       st_max_speed = max(st_max_speed, 25 * station_length);
00464       max_speed = min(max_speed, st_max_speed);
00465     }
00466   }
00467 
00468   int mass = v->u.rail.cached_weight;
00469   int power = v->u.rail.cached_power * 746;
00470   max_speed = min(max_speed, v->u.rail.cached_max_speed);
00471 
00472   int num = 0; //number of vehicles, change this into the number of axles later
00473   int incl = 0;
00474   int drag_coeff = 20; //[1e-4]
00475   for (const Vehicle *u = v; u != NULL; u = u->Next()) {
00476     num++;
00477     drag_coeff += 3;
00478 
00479     if (u->u.rail.track == TRACK_BIT_DEPOT) max_speed = min(max_speed, 61);
00480 
00481     if (HasBit(u->u.rail.flags, VRF_GOINGUP)) {
00482       incl += u->u.rail.cached_veh_weight * 60; //3% slope, quite a bit actually
00483     } else if (HasBit(u->u.rail.flags, VRF_GOINGDOWN)) {
00484       incl -= u->u.rail.cached_veh_weight * 60;
00485     }
00486   }
00487 
00488   v->max_speed = max_speed;
00489 
00490   const int area = 120;
00491   const int friction = 35; //[1e-3]
00492   int resistance;
00493   if (v->u.rail.railtype != RAILTYPE_MAGLEV) {
00494     resistance = 13 * mass / 10;
00495     resistance += 60 * num;
00496     resistance += friction * mass * speed / 1000;
00497     resistance += (area * drag_coeff * speed * speed) / 10000;
00498   } else {
00499     resistance = (area * (drag_coeff / 2) * speed * speed) / 10000;
00500   }
00501   resistance += incl;
00502   resistance *= 4; //[N]
00503 
00504   /* Due to the mph to m/s conversion below, at speeds below 3 mph the force is
00505    * actually double the train's power */
00506   const int max_te = v->u.rail.cached_max_te; // [N]
00507   int force;
00508   if (speed > 2) {
00509     switch (v->u.rail.railtype) {
00510       case RAILTYPE_RAIL:
00511       case RAILTYPE_ELECTRIC:
00512       case RAILTYPE_MONO:
00513         force = power / speed; //[N]
00514         force *= 22;
00515         force /= 10;
00516         if (mode == AM_ACCEL && force > max_te) force = max_te;
00517         break;
00518 
00519       default: NOT_REACHED();
00520       case RAILTYPE_MAGLEV:
00521         force = power / 25;
00522         break;
00523     }
00524   } else {
00525     /* "kickoff" acceleration */
00526     force = (mode == AM_ACCEL && v->u.rail.railtype != RAILTYPE_MAGLEV) ? min(max_te, power) : power;
00527     force = max(force, (mass * 8) + resistance);
00528   }
00529 
00530   if (force <= 0) force = 10000;
00531 
00532   if (v->u.rail.railtype != RAILTYPE_MAGLEV) force = min(force, mass * 10 * 200);
00533 
00534   if (mode == AM_ACCEL) {
00535     return (force - resistance) / (mass * 4);
00536   } else {
00537     return min((-force - resistance) / (mass * 4), -10000 / (mass * 4));
00538   }
00539 }
00540 
00541 void UpdateTrainAcceleration(Vehicle *v)
00542 {
00543   assert(IsFrontEngine(v));
00544 
00545   v->max_speed = v->u.rail.cached_max_speed;
00546 
00547   uint power = v->u.rail.cached_power;
00548   uint weight = v->u.rail.cached_weight;
00549   assert(weight != 0);
00550   v->acceleration = Clamp(power / weight * 4, 1, 255);
00551 }
00552 
00553 SpriteID Train::GetImage(Direction direction) const
00554 {
00555   uint8 spritenum = this->spritenum;
00556   SpriteID sprite;
00557 
00558   if (HasBit(this->u.rail.flags, VRF_REVERSE_DIRECTION)) direction = ReverseDir(direction);
00559 
00560   if (is_custom_sprite(spritenum)) {
00561     sprite = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)));
00562     if (sprite != 0) return sprite;
00563 
00564     spritenum = GetEngine(this->engine_type)->image_index;
00565   }
00566 
00567   sprite = _engine_sprite_base[spritenum] + ((direction + _engine_sprite_add[spritenum]) & _engine_sprite_and[spritenum]);
00568 
00569   if (this->cargo.Count() >= this->cargo_cap / 2U) sprite += _wagon_full_adder[spritenum];
00570 
00571   return sprite;
00572 }
00573 
00574 static SpriteID GetRailIcon(EngineID engine, bool rear_head, int &y)
00575 {
00576   Direction dir = rear_head ? DIR_E : DIR_W;
00577   uint8 spritenum = RailVehInfo(engine)->image_index;
00578 
00579   if (is_custom_sprite(spritenum)) {
00580     SpriteID sprite = GetCustomVehicleIcon(engine, dir);
00581     if (sprite != 0) {
00582       y += _traininfo_vehicle_pitch; // TODO Make this per-GRF
00583       return sprite;
00584     }
00585 
00586     spritenum = GetEngine(engine)->image_index;
00587   }
00588 
00589   if (rear_head) spritenum++;
00590 
00591   return ((6 + _engine_sprite_add[spritenum]) & _engine_sprite_and[spritenum]) + _engine_sprite_base[spritenum];
00592 }
00593 
00594 void DrawTrainEngine(int x, int y, EngineID engine, SpriteID pal)
00595 {
00596   if (RailVehInfo(engine)->railveh_type == RAILVEH_MULTIHEAD) {
00597     int yf = y;
00598     int yr = y;
00599 
00600     SpriteID spritef = GetRailIcon(engine, false, yf);
00601     SpriteID spriter = GetRailIcon(engine, true, yr);
00602     DrawSprite(spritef, pal, x - 14, yf);
00603     DrawSprite(spriter, pal, x + 15, yr);
00604   } else {
00605     SpriteID sprite = GetRailIcon(engine, false, y);
00606     DrawSprite(sprite, pal, x, y);
00607   }
00608 }
00609 
00610 static CommandCost CmdBuildRailWagon(EngineID engine, TileIndex tile, uint32 flags)
00611 {
00612   const RailVehicleInfo *rvi = RailVehInfo(engine);
00613   CommandCost value(EXPENSES_NEW_VEHICLES, (GetEngineProperty(engine, 0x17, rvi->cost_factor) * _price.build_railwagon) >> 8);
00614 
00615   uint num_vehicles = 1 + CountArticulatedParts(engine, false);
00616 
00617   if (!(flags & DC_QUERY_COST)) {
00618     /* Check that the wagon can drive on the track in question */
00619     if (!IsCompatibleRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR;
00620 
00621     /* Allow for the wagon and the articulated parts, plus one to "terminate" the list. */
00622     Vehicle **vl = AllocaM(Vehicle*, num_vehicles + 1);
00623     memset(vl, 0, sizeof(*vl) * (num_vehicles + 1));
00624 
00625     if (!Vehicle::AllocateList(vl, num_vehicles))
00626       return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
00627 
00628     if (flags & DC_EXEC) {
00629       Vehicle *v = vl[0];
00630       v->spritenum = rvi->image_index;
00631 
00632       Vehicle *u = NULL;
00633 
00634       Vehicle *w;
00635       FOR_ALL_VEHICLES(w) {
00636         if (w->type == VEH_TRAIN && w->tile == tile &&
00637             IsFreeWagon(w) && w->engine_type == engine &&
00638             !HASBITS(w->vehstatus, VS_CRASHED)) {          
00639           u = GetLastVehicleInChain(w);
00640           break;
00641         }
00642       }
00643 
00644       v = new (v) Train();
00645       v->engine_type = engine;
00646 
00647       DiagDirection dir = GetRailDepotDirection(tile);
00648 
00649       v->direction = DiagDirToDir(dir);
00650       v->tile = tile;
00651 
00652       int x = TileX(tile) * TILE_SIZE | _vehicle_initial_x_fract[dir];
00653       int y = TileY(tile) * TILE_SIZE | _vehicle_initial_y_fract[dir];
00654 
00655       v->x_pos = x;
00656       v->y_pos = y;
00657       v->z_pos = GetSlopeZ(x, y);
00658       v->owner = _current_company;
00659       v->u.rail.track = TRACK_BIT_DEPOT;
00660       v->vehstatus = VS_HIDDEN | VS_DEFPAL;
00661 
00662 //      v->subtype = 0;
00663       SetTrainWagon(v);
00664 
00665       if (u != NULL) {
00666         u->SetNext(v);
00667       } else {
00668         SetFreeWagon(v);
00669         InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
00670       }
00671 
00672       v->cargo_type = rvi->cargo_type;
00673 //      v->cargo_subtype = 0;
00674       v->cargo_cap = rvi->capacity;
00675       v->value = value.GetCost();
00676 //      v->day_counter = 0;
00677 
00678       v->u.rail.railtype = rvi->railtype;
00679 
00680       v->build_year = _cur_year;
00681       v->cur_image = 0xAC2;
00682       v->random_bits = VehicleRandomBits();
00683 
00684       v->group_id = DEFAULT_GROUP;
00685 
00686       AddArticulatedParts(vl, VEH_TRAIN);
00687 
00688       _new_vehicle_id = v->index;
00689 
00690       VehiclePositionChanged(v);
00691       TrainConsistChanged(v->First(), false);
00692       UpdateTrainGroupID(v->First());
00693 
00694       InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
00695       if (IsLocalCompany()) {
00696         InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Train window
00697       }
00698       GetCompany(_current_company)->num_engines[engine]++;
00699     }
00700   }
00701 
00702   return value;
00703 }
00704 
00706 static void NormalizeTrainVehInDepot(const Vehicle *u)
00707 {
00708   const Vehicle *v;
00709 
00710   FOR_ALL_VEHICLES(v) {
00711     if (v->type == VEH_TRAIN && IsFreeWagon(v) &&
00712         v->tile == u->tile &&
00713         v->u.rail.track == TRACK_BIT_DEPOT) {
00714       if (CmdFailed(DoCommand(0, v->index | (u->index << 16), 1, DC_EXEC,
00715           CMD_MOVE_RAIL_VEHICLE)))
00716         break;
00717     }
00718   }
00719 }
00720 
00721 static CommandCost EstimateTrainCost(EngineID engine, const RailVehicleInfo *rvi)
00722 {
00723   return CommandCost(EXPENSES_NEW_VEHICLES, GetEngineProperty(engine, 0x17, rvi->cost_factor) * (_price.build_railvehicle >> 3) >> 5);
00724 }
00725 
00726 static void AddRearEngineToMultiheadedTrain(Vehicle *v, Vehicle *u, bool building)
00727 {
00728   u = new (u) Train();
00729   u->direction = v->direction;
00730   u->owner = v->owner;
00731   u->tile = v->tile;
00732   u->x_pos = v->x_pos;
00733   u->y_pos = v->y_pos;
00734   u->z_pos = v->z_pos;
00735   u->u.rail.track = TRACK_BIT_DEPOT;
00736   u->vehstatus = v->vehstatus & ~VS_STOPPED;
00737 //  u->subtype = 0;
00738   SetMultiheaded(u);
00739   u->spritenum = v->spritenum + 1;
00740   u->cargo_type = v->cargo_type;
00741   u->cargo_subtype = v->cargo_subtype;
00742   u->cargo_cap = v->cargo_cap;
00743   u->u.rail.railtype = v->u.rail.railtype;
00744   if (building) v->SetNext(u);
00745   u->engine_type = v->engine_type;
00746   u->build_year = v->build_year;
00747   if (building) v->value >>= 1;
00748   u->value = v->value;
00749   u->cur_image = 0xAC2;
00750   u->random_bits = VehicleRandomBits();
00751   VehiclePositionChanged(u);
00752 }
00753 
00760 CommandCost CmdBuildRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2, const char *text)
00761 {
00762   /* Check if the engine-type is valid (for the company) */
00763   if (!IsEngineBuildable(p1, VEH_TRAIN, _current_company)) return_cmd_error(STR_RAIL_VEHICLE_NOT_AVAILABLE);
00764 
00765   /* Check if the train is actually being built in a depot belonging
00766    * to the company. Doesn't matter if only the cost is queried */
00767   if (!(flags & DC_QUERY_COST)) {
00768     if (!IsRailDepotTile(tile)) return CMD_ERROR;
00769     if (!IsTileOwner(tile, _current_company)) return CMD_ERROR;
00770   }
00771 
00772   const RailVehicleInfo *rvi = RailVehInfo(p1);
00773 
00774   if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildRailWagon(p1, tile, flags);
00775 
00776   CommandCost value = EstimateTrainCost(p1, rvi);
00777 
00778   uint num_vehicles =
00779     (rvi->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1) +
00780     CountArticulatedParts(p1, false);
00781 
00782   if (!(flags & DC_QUERY_COST)) {
00783     /* Check if depot and new engine uses the same kind of tracks *
00784      * We need to see if the engine got power on the tile to avoid eletric engines in non-electric depots */
00785     if (!HasPowerOnRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR;
00786 
00787     /* Allow for the dual-heads and the articulated parts, plus one to "terminate" the list. */
00788     Vehicle **vl = AllocaM(Vehicle*, num_vehicles + 1);
00789     memset(vl, 0, sizeof(*vl) * (num_vehicles + 1));
00790 
00791     if (!Vehicle::AllocateList(vl, num_vehicles)) {
00792       return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
00793     }
00794 
00795     Vehicle *v = vl[0];
00796 
00797     UnitID unit_num = (flags & DC_AUTOREPLACE) ? 0 : GetFreeUnitNumber(VEH_TRAIN);
00798     if (unit_num > _settings_game.vehicle.max_trains)
00799       return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
00800 
00801     if (flags & DC_EXEC) {
00802       DiagDirection dir = GetRailDepotDirection(tile);
00803       int x = TileX(tile) * TILE_SIZE + _vehicle_initial_x_fract[dir];
00804       int y = TileY(tile) * TILE_SIZE + _vehicle_initial_y_fract[dir];
00805 
00806       v = new (v) Train();
00807       v->unitnumber = unit_num;
00808       v->direction = DiagDirToDir(dir);
00809       v->tile = tile;
00810       v->owner = _current_company;
00811       v->x_pos = x;
00812       v->y_pos = y;
00813       v->z_pos = GetSlopeZ(x, y);
00814 //      v->running_ticks = 0;
00815       v->u.rail.track = TRACK_BIT_DEPOT;
00816       v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
00817       v->spritenum = rvi->image_index;
00818       v->cargo_type = rvi->cargo_type;
00819 //      v->cargo_subtype = 0;
00820       v->cargo_cap = rvi->capacity;
00821       v->max_speed = rvi->max_speed;
00822       v->value = value.GetCost();
00823       v->last_station_visited = INVALID_STATION;
00824 //      v->dest_tile = 0;
00825 
00826       v->engine_type = p1;
00827 
00828       const Engine *e = GetEngine(p1);
00829       v->reliability = e->reliability;
00830       v->reliability_spd_dec = e->reliability_spd_dec;
00831       v->max_age = e->lifelength * 366;
00832 
00833       v->name = NULL;
00834       v->u.rail.railtype = rvi->railtype;
00835       _new_vehicle_id = v->index;
00836 
00837       v->service_interval = _settings_game.vehicle.servint_trains;
00838       v->date_of_last_service = _date;
00839       v->build_year = _cur_year;
00840       v->cur_image = 0xAC2;
00841       v->random_bits = VehicleRandomBits();
00842 
00843 //      v->vehicle_flags = 0;
00844       if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
00845 
00846       v->group_id = DEFAULT_GROUP;
00847 
00848 //      v->subtype = 0;
00849       SetFrontEngine(v);
00850       SetTrainEngine(v);
00851 
00852       VehiclePositionChanged(v);
00853 
00854       if (rvi->railveh_type == RAILVEH_MULTIHEAD) {
00855         SetMultiheaded(v);
00856         AddRearEngineToMultiheadedTrain(vl[0], vl[1], true);
00857         /* Now we need to link the front and rear engines together
00858          * other_multiheaded_part is the pointer that links to the other half of the engine
00859          * vl[0] is the front and vl[1] is the rear
00860          */
00861         vl[0]->u.rail.other_multiheaded_part = vl[1];
00862         vl[1]->u.rail.other_multiheaded_part = vl[0];
00863       } else {
00864         AddArticulatedParts(vl, VEH_TRAIN);
00865       }
00866 
00867       TrainConsistChanged(v, false);
00868       UpdateTrainGroupID(v);
00869 
00870       if (!HasBit(p2, 1) && !(flags & DC_AUTOREPLACE)) { // check if the cars should be added to the new vehicle
00871         NormalizeTrainVehInDepot(v);
00872       }
00873 
00874       InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
00875       InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
00876       InvalidateWindow(WC_COMPANY, v->owner);
00877       if (IsLocalCompany()) {
00878         InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Train window
00879       }
00880 
00881       GetCompany(_current_company)->num_engines[p1]++;
00882     }
00883   }
00884 
00885   return value;
00886 }
00887 
00888 
00889 /* Check if all the wagons of the given train are in a depot, returns the
00890  * number of cars (including loco) then. If not it returns -1 */
00891 int CheckTrainInDepot(const Vehicle *v, bool needs_to_be_stopped)
00892 {
00893   TileIndex tile = v->tile;
00894 
00895   /* check if stopped in a depot */
00896   if (!IsRailDepotTile(tile) || v->cur_speed != 0) return -1;
00897 
00898   int count = 0;
00899   for (; v != NULL; v = v->Next()) {
00900     /* This count is used by the depot code to determine the number of engines
00901      * in the consist. Exclude articulated parts so that autoreplacing to
00902      * engines with more articulated parts than before works correctly.
00903      *
00904      * Also skip counting rear ends of multiheaded engines */
00905     if (!IsArticulatedPart(v) && !IsRearDualheaded(v)) count++;
00906     if (v->u.rail.track != TRACK_BIT_DEPOT || v->tile != tile ||
00907         (IsFrontEngine(v) && needs_to_be_stopped && !(v->vehstatus & VS_STOPPED))) {
00908       return -1;
00909     }
00910   }
00911 
00912   return count;
00913 }
00914 
00915 /* Used to check if the train is inside the depot and verifying that the VS_STOPPED flag is set */
00916 int CheckTrainStoppedInDepot(const Vehicle *v)
00917 {
00918   return CheckTrainInDepot(v, true);
00919 }
00920 
00921 /* Used to check if the train is inside the depot, but not checking the VS_STOPPED flag */
00922 inline bool CheckTrainIsInsideDepot(const Vehicle *v)
00923 {
00924   return CheckTrainInDepot(v, false) > 0;
00925 }
00926 
00933 static Vehicle *UnlinkWagon(Vehicle *v, Vehicle *first)
00934 {
00935   /* unlinking the first vehicle of the chain? */
00936   if (v == first) {
00937     v = GetNextVehicle(v);
00938     if (v == NULL) return NULL;
00939 
00940     if (IsTrainWagon(v)) SetFreeWagon(v);
00941 
00942     /* First can be an articulated engine, meaning GetNextVehicle() isn't
00943      * v->Next(). Thus set the next vehicle of the last articulated part
00944      * and the last articulated part is just before the next vehicle (v). */
00945     v->Previous()->SetNext(NULL);
00946 
00947     return v;
00948   }
00949 
00950   Vehicle *u;
00951   for (u = first; GetNextVehicle(u) != v; u = GetNextVehicle(u)) {}
00952   GetLastEnginePart(u)->SetNext(GetNextVehicle(v));
00953   return first;
00954 }
00955 
00956 static Vehicle *FindGoodVehiclePos(const Vehicle *src)
00957 {
00958   Vehicle *dst;
00959   EngineID eng = src->engine_type;
00960   TileIndex tile = src->tile;
00961 
00962   FOR_ALL_VEHICLES(dst) {
00963     if (dst->type == VEH_TRAIN && IsFreeWagon(dst) && dst->tile == tile && !HASBITS(dst->vehstatus, VS_CRASHED)) {
00964       /* check so all vehicles in the line have the same engine. */
00965       Vehicle *v = dst;
00966 
00967       while (v->engine_type == eng) {
00968         v = v->Next();
00969         if (v == NULL) return dst;
00970       }
00971     }
00972   }
00973 
00974   return NULL;
00975 }
00976 
00977 /*
00978  * add a vehicle v behind vehicle dest
00979  * use this function since it sets flags as needed
00980  */
00981 static void AddWagonToConsist(Vehicle *v, Vehicle *dest)
00982 {
00983   UnlinkWagon(v, v->First());
00984   if (dest == NULL) return;
00985 
00986   Vehicle *next = dest->Next();
00987   v->SetNext(NULL);
00988   dest->SetNext(v);
00989   v->SetNext(next);
00990   ClearFreeWagon(v);
00991   ClearFrontEngine(v);
00992 }
00993 
00994 /*
00995  * move around on the train so rear engines are placed correctly according to the other engines
00996  * always call with the front engine
00997  */
00998 static void NormaliseTrainConsist(Vehicle *v)
00999 {
01000   if (IsFreeWagon(v)) return;
01001 
01002   assert(IsFrontEngine(v));
01003 
01004   for (; v != NULL; v = GetNextVehicle(v)) {
01005     if (!IsMultiheaded(v) || !IsTrainEngine(v)) continue;
01006 
01007     /* make sure that there are no free cars before next engine */
01008     Vehicle *u;
01009     for (u = v; u->Next() != NULL && !IsTrainEngine(u->Next()); u = u->Next()) {}
01010 
01011     if (u == v->u.rail.other_multiheaded_part) continue;
01012     AddWagonToConsist(v->u.rail.other_multiheaded_part, u);
01013   }
01014 }
01015 
01025 CommandCost CmdMoveRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2, const char *text)
01026 {
01027   VehicleID s = GB(p1, 0, 16);
01028   VehicleID d = GB(p1, 16, 16);
01029 
01030   if (!IsValidVehicleID(s)) return CMD_ERROR;
01031 
01032   Vehicle *src = GetVehicle(s);
01033 
01034   if (src->type != VEH_TRAIN || !CheckOwnership(src->owner)) return CMD_ERROR;
01035 
01036   /* Do not allow moving crashed vehicles inside the depot, it is likely to cause asserts later */
01037   if (HASBITS(src->vehstatus, VS_CRASHED)) return CMD_ERROR;
01038 
01039   /* if nothing is selected as destination, try and find a matching vehicle to drag to. */
01040   Vehicle *dst;
01041   if (d == INVALID_VEHICLE) {
01042     dst = IsTrainEngine(src) ? NULL : FindGoodVehiclePos(src);
01043   } else {
01044     if (!IsValidVehicleID(d)) return CMD_ERROR;
01045     dst = GetVehicle(d);
01046     if (dst->type != VEH_TRAIN || !CheckOwnership(dst->owner)) return CMD_ERROR;
01047 
01048     /* Do not allow appending to crashed vehicles, too */
01049     if (HASBITS(dst->vehstatus, VS_CRASHED)) return CMD_ERROR;
01050   }
01051 
01052   /* if an articulated part is being handled, deal with its parent vehicle */
01053   while (IsArticulatedPart(src)) src = src->Previous();
01054   if (dst != NULL) {
01055     while (IsArticulatedPart(dst)) dst = dst->Previous();
01056   }
01057 
01058   /* don't move the same vehicle.. */
01059   if (src == dst) return CommandCost();
01060 
01061   /* locate the head of the two chains */
01062   Vehicle *src_head = src->First();
01063   Vehicle *dst_head;
01064   if (dst != NULL) {
01065     dst_head = dst->First();
01066     if (dst_head->tile != src_head->tile) return CMD_ERROR;
01067     /* Now deal with articulated part of destination wagon */
01068     dst = GetLastEnginePart(dst);
01069   } else {
01070     dst_head = NULL;
01071   }
01072 
01073   if (IsRearDualheaded(src)) return_cmd_error(STR_REAR_ENGINE_FOLLOW_FRONT_ERROR);
01074 
01075   /* when moving all wagons, we can't have the same src_head and dst_head */
01076   if (HasBit(p2, 0) && src_head == dst_head) return CommandCost();
01077 
01078   /* check if all vehicles in the source train are stopped inside a depot. */
01079   int src_len = CheckTrainStoppedInDepot(src_head);
01080   if (src_len < 0) return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
01081 
01082   if ((flags & DC_AUTOREPLACE) == 0) {
01083     /* Check whether there are more than 'max_len' train units (articulated parts and rear heads do not count) in the new chain */
01084     int max_len = _settings_game.