# train_cmd.cpp

Go to the documentation of this file.

    00001 /* $Id: train_cmd.cpp 14385 2008-09-22 19:57:31Z rubidium $ */
    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 "timetable.h"
    00015 #include "articulated_vehicles.h"
    00016 #include "command_func.h"
    00017 #include "pathfind.h"
    00018 #include "npf.h"
    00019 #include "station.h"
    00020 #include "news.h"
    00021 #include "engine.h"
    00022 #include "player_func.h"
    00023 #include "player_base.h"
    00024 #include "depot.h"
    00025 #include "waypoint.h"
    00026 #include "vehicle_gui.h"
    00027 #include "train.h"
    00028 #include "bridge.h"
    00029 #include "newgrf_callbacks.h"
    00030 #include "newgrf_engine.h"
    00031 #include "newgrf_sound.h"
    00032 #include "newgrf_text.h"
    00033 #include "direction_func.h"
    00034 #include "yapf/yapf.h"
    00035 #include "cargotype.h"
    00036 #include "group.h"
    00037 #include "table/sprites.h"
    00038 #include "tunnelbridge_map.h"
    00039 #include "strings_func.h"
    00040 #include "functions.h"
    00041 #include "window_func.h"
    00042 #include "date_func.h"
    00043 #include "vehicle_func.h"
    00044 #include "sound_func.h"
    00045 #include "signal_func.h"
    00046 #include "variables.h"
    00047 #include "autoreplace_gui.h"
    00048 #include "gfx_func.h"
    00049 #include "settings_type.h"
    00050 #include "network/network.h"
    00051
    00052 #include "table/strings.h"
    00053 #include "table/train_cmd.h"
    00054
    00055 static bool TrainCheckIfLineEnds(Vehicle *v);
    00056 static void TrainController(Vehicle *v, Vehicle *nomove, bool update_image);
    00057 static TileIndex TrainApproachingCrossingTile(const Vehicle *v);
    00058
    00059 static const byte _vehicle_initial_x_fract[4] = {10, 8, 4,  8};
    00060 static const byte _vehicle_initial_y_fract[4] = { 8, 4, 8, 10};
    00061
    00062
    00070 static inline DiagDirection TrainExitDir(Direction direction, TrackBits track)
    00071 {
    00072   static const TrackBits state_dir_table[DIAGDIR_END] = { TRACK_BIT_RIGHT, TRACK_BIT_LOWER, TRACK_BIT_LEFT, TRACK_BIT_UPPER };
    00073
    00074   DiagDirection diagdir = DirToDiagDir(direction);
    00075
    00076   /* Determine the diagonal direction in which we will exit this tile */
    00077   if (!HasBit(direction, 0) && track != state_dir_table[diagdir]) {
    00078     diagdir = ChangeDiagDir(diagdir, DIAGDIRDIFF_90LEFT);
    00079   }
    00080
    00081   return diagdir;
    00082 }
    00083
    00084
    00089 byte FreightWagonMult(CargoID cargo)
    00090 {
    00091   if (!GetCargo(cargo)->is_freight) return 1;
    00092   return _patches.freight_trains;
    00093 }
    00094
    00095
    00100 void TrainPowerChanged(Vehicle* v)
    00101 {
    00102   uint32 total_power = 0;
    00103   uint32 max_te = 0;
    00104
    00105   for (const Vehicle *u = v; u != NULL; u = u->Next()) {
    00106     /* Power is not added for articulated parts */
    00107     if (IsArticulatedPart(u)) continue;
    00108
    00109     RailType railtype = GetRailType(u->tile);
    00110     bool engine_has_power = HasPowerOnRail(u->u.rail.railtype, railtype);
    00111     bool wagon_has_power  = HasPowerOnRail(v->u.rail.railtype, railtype);
    00112
    00113     const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type);
    00114
    00115     if (engine_has_power) {
    00116       uint16 power = GetVehicleProperty(u, 0x0B, rvi_u->power);
    00117       if (power != 0) {
    00118         /* Halve power for multiheaded parts */
    00119         if (IsMultiheaded(u)) power /= 2;
    00120
    00121         total_power += power;
    00122         /* Tractive effort in (tonnes * 1000 * 10 =) N */
    00123         max_te += (u->u.rail.cached_veh_weight * 10000 * GetVehicleProperty(u, 0x1F, rvi_u->tractive_effort)) / 256;
    00124       }
    00125     }
    00126
    00127     if (HasBit(u->u.rail.flags, VRF_POWEREDWAGON) && (wagon_has_power)) {
    00128       total_power += RailVehInfo(u->u.rail.first_engine)->pow_wag_power;
    00129     }
    00130   }
    00131
    00132   if (v->u.rail.cached_power != total_power || v->u.rail.cached_max_te != max_te) {
    00133     /* If it has no power (no catenary), stop the train */
    00134     if (total_power == 0) v->vehstatus |= VS_STOPPED;
    00135
    00136     v->u.rail.cached_power = total_power;
    00137     v->u.rail.cached_max_te = max_te;
    00138     InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
    00139     InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
    00140   }
    00141 }
    00142
    00143
    00149 static void TrainCargoChanged(Vehicle* v)
    00150 {
    00151   uint32 weight = 0;
    00152
    00153   for (Vehicle *u = v; u != NULL; u = u->Next()) {
    00154     uint32 vweight = GetCargo(u->cargo_type)->weight * u->cargo.Count() * FreightWagonMult(u->cargo_type) / 16;
    00155
    00156     /* Vehicle weight is not added for articulated parts. */
    00157     if (!IsArticulatedPart(u)) {
    00158       /* vehicle weight is the sum of the weight of the vehicle and the weight of its cargo */
    00159       vweight += GetVehicleProperty(u, 0x16, RailVehInfo(u->engine_type)->weight);
    00160
    00161       /* powered wagons have extra weight added */
    00162       if (HasBit(u->u.rail.flags, VRF_POWEREDWAGON))
    00163         vweight += RailVehInfo(u->u.rail.first_engine)->pow_wag_weight;
    00164     }
    00165
    00166     /* consist weight is the sum of the weight of all vehicles in the consist */
    00167     weight += vweight;
    00168
    00169     /* store vehicle weight in cache */
    00170     u->u.rail.cached_veh_weight = vweight;
    00171   }
    00172
    00173   /* store consist weight in cache */
    00174   v->u.rail.cached_weight = weight;
    00175
    00176   /* Now update train power (tractive effort is dependent on weight) */
    00177   TrainPowerChanged(v);
    00178 }
    00179
    00180
    00185 static void RailVehicleLengthChanged(const Vehicle *u)
    00186 {
    00187   extern const GRFFile *_engine_grf[TOTAL_NUM_ENGINES];
    00188   if (_engine_grf[u->engine_type] == NULL) return;
    00189
    00190   uint32 grfid = _engine_grf[u->engine_type]->grfid;
    00191   GRFConfig *grfconfig = GetGRFConfig(grfid);
    00192   if (!HasBit(grfconfig->grf_bugs, GBUG_VEH_LENGTH)) {
    00193     SetBit(grfconfig->grf_bugs, GBUG_VEH_LENGTH);
    00194     SetDParamStr(0, grfconfig->name);
    00195     SetDParam(1, u->engine_type);
    00196     ShowErrorMessage(STR_NEWGRF_BROKEN_VEHICLE_LENGTH, STR_NEWGRF_BROKEN, 0, 0);
    00197
    00198     /* debug output */
    00199     char buffer[512];
    00200
    00201     SetDParamStr(0, grfconfig->name);
    00202     GetString(buffer, STR_NEWGRF_BROKEN, lastof(buffer));
    00203     DEBUG(grf, 0, "%s", buffer + 3);
    00204
    00205     SetDParam(1, u->engine_type);
    00206     GetString(buffer, STR_NEWGRF_BROKEN_VEHICLE_LENGTH, lastof(buffer));
    00207     DEBUG(grf, 0, "%s", buffer + 3);
    00208
    00209     if (!_networking) _pause_game = -1;
    00210   }
    00211 }
    00212
    00214 void CheckTrainsLengths()
    00215 {
    00216   const Vehicle *v;
    00217
    00218   FOR_ALL_VEHICLES(v) {
    00219     if (v->type == VEH_TRAIN && v->First() == v && !(v->vehstatus & VS_CRASHED)) {
    00220       for (const Vehicle *u = v, *w = v->Next(); w != NULL; u = w, w = w->Next()) {
    00221         if (u->u.rail.track != TRACK_BIT_DEPOT) {
    00222           if ((w->u.rail.track != TRACK_BIT_DEPOT &&
    00223               max(abs(u->x_pos - w->x_pos), abs(u->y_pos - w->y_pos)) != u->u.rail.cached_veh_length) ||
    00224               (w->u.rail.track == TRACK_BIT_DEPOT && TicksToLeaveDepot(u) <= 0)) {
    00225             SetDParam(0, v->index);
    00226             SetDParam(1, v->owner);
    00227             ShowErrorMessage(INVALID_STRING_ID, STR_BROKEN_VEHICLE_LENGTH, 0, 0);
    00228
    00229             if (!_networking) _pause_game = -1;
    00230           }
    00231         }
    00232       }
    00233     }
    00234   }
    00235 }
    00236
    00244 void TrainConsistChanged(Vehicle *v, bool same_length)
    00245 {
    00246   uint16 max_speed = 0xFFFF;
    00247
    00248   assert(v->type == VEH_TRAIN);
    00249   assert(IsFrontEngine(v) || IsFreeWagon(v));
    00250
    00251   const RailVehicleInfo *rvi_v = RailVehInfo(v->engine_type);
    00252   EngineID first_engine = IsFrontEngine(v) ? v->engine_type : INVALID_ENGINE;
    00253   v->u.rail.cached_total_length = 0;
    00254   v->u.rail.compatible_railtypes = RAILTYPES_NONE;
    00255
    00256   bool train_can_tilt = true;
    00257
    00258   for (Vehicle *u = v; u != NULL; u = u->Next()) {
    00259     const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type);
    00260
    00261     /* Check the v->first cache. */
    00262     assert(u->First() == v);
    00263
    00264     /* update the 'first engine' */
    00265     u->u.rail.first_engine = v == u ? INVALID_ENGINE : first_engine;
    00266     u->u.rail.railtype = rvi_u->railtype;
    00267
    00268     /* Set user defined data to its default value */
    00269     u->u.rail.user_def_data = rvi_u->user_def_data;
    00270   }
    00271
    00272   for (Vehicle *u = v; u != NULL; u = u->Next()) {
    00273     /* Update user defined data (must be done before other properties) */
    00274     u->u.rail.user_def_data = GetVehicleProperty(u, 0x25, u->u.rail.user_def_data);
    00275   }
    00276
    00277   for (Vehicle *u = v; u != NULL; u = u->Next()) {
    00278     const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type);
    00279
    00280     if (!HasBit(EngInfo(u->engine_type)->misc_flags, EF_RAIL_TILTS)) train_can_tilt = false;
    00281
    00282     if (IsTrainEngine(u)) first_engine = u->engine_type;
    00283
    00284     /* Cache wagon override sprite group. NULL is returned if there is none */
    00285     u->u.rail.cached_override = GetWagonOverrideSpriteSet(u->engine_type, u->cargo_type, u->u.rail.first_engine);
    00286
    00287     /* Reset color map */
    00288     u->colormap = PAL_NONE;
    00289
    00290     if (rvi_u->visual_effect != 0) {
    00291       u->u.rail.cached_vis_effect = rvi_u->visual_effect;
    00292     } else {
    00293       if (IsTrainWagon(u) || IsArticulatedPart(u)) {
    00294         /* Wagons and articulated parts have no effect by default */
    00295         u->u.rail.cached_vis_effect = 0x40;
    00296       } else if (rvi_u->engclass == 0) {
    00297         /* Steam is offset by -4 units */
    00298         u->u.rail.cached_vis_effect = 4;
    00299       } else {
    00300         /* Diesel fumes and sparks come from the centre */
    00301         u->u.rail.cached_vis_effect = 8;
    00302       }
    00303     }
    00304
    00305     if (!IsArticulatedPart(u)) {
    00306       /* Check powered wagon / visual effect callback */
    00307       if (HasBit(EngInfo(u->engine_type)->callbackmask, CBM_TRAIN_WAGON_POWER)) {
    00308         uint16 callback = GetVehicleCallback(CBID_TRAIN_WAGON_POWER, 0, 0, u->engine_type, u);
    00309
    00310         if (callback != CALLBACK_FAILED) u->u.rail.cached_vis_effect = GB(callback, 0, 8);
    00311       }
    00312
    00313       if (rvi_v->pow_wag_power != 0 && rvi_u->railveh_type == RAILVEH_WAGON &&
    00314         UsesWagonOverride(u) && !HasBit(u->u.rail.cached_vis_effect, 7)) {
    00315         /* wagon is powered */
    00316         SetBit(u->u.rail.flags, VRF_POWEREDWAGON); // cache 'powered' status
    00317       } else {
    00318         ClrBit(u->u.rail.flags, VRF_POWEREDWAGON);
    00319       }
    00320
    00321       /* Do not count powered wagons for the compatible railtypes, as wagons always
    00322          have railtype normal */
    00323       if (rvi_u->power > 0) {
    00324         v->u.rail.compatible_railtypes |= GetRailTypeInfo(u->u.rail.railtype)->powered_railtypes;
    00325       }
    00326
    00327       /* Some electric engines can be allowed to run on normal rail. It happens to all
    00328        * existing electric engines when elrails are disabled and then re-enabled */
    00329       if (HasBit(u->u.rail.flags, VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL)) {
    00330         u->u.rail.railtype = RAILTYPE_RAIL;
    00331         u->u.rail.compatible_railtypes |= RAILTYPES_RAIL;
    00332       }
    00333
    00334       /* max speed is the minimum of the speed limits of all vehicles in the consist */
    00335       if ((rvi_u->railveh_type != RAILVEH_WAGON || _patches.wagon_speed_limits) && !UsesWagonOverride(u)) {
    00336         uint16 speed = GetVehicleProperty(u, 0x09, rvi_u->max_speed);
    00337         if (speed != 0) max_speed = min(speed, max_speed);
    00338       }
    00339     }
    00340
    00341     if (u->cargo_type == rvi_u->cargo_type && u->cargo_subtype == 0) {
    00342       /* Set cargo capacity if we've not been refitted */
    00343       u->cargo_cap = GetVehicleProperty(u, 0x14, rvi_u->capacity);
    00344     }
    00345
    00346     /* check the vehicle length (callback) */
    00347     uint16 veh_len = CALLBACK_FAILED;
    00348     if (HasBit(EngInfo(u->engine_type)->callbackmask, CBM_VEHICLE_LENGTH)) {
    00349       veh_len = GetVehicleCallback(CBID_VEHICLE_LENGTH, 0, 0, u->engine_type, u);
    00350     }
    00351     if (veh_len == CALLBACK_FAILED) veh_len = rvi_u->shorten_factor;
    00352     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
    00353
    00354     /* verify length hasn't changed */
    00355     if (same_length && veh_len != u->u.rail.cached_veh_length) RailVehicleLengthChanged(u);
    00356
    00357     /* update vehicle length? */
    00358     if (!same_length) u->u.rail.cached_veh_length = veh_len;
    00359
    00360     v->u.rail.cached_total_length += u->u.rail.cached_veh_length;
    00361   }
    00362
    00363   /* store consist weight/max speed in cache */
    00364   v->u.rail.cached_max_speed = max_speed;
    00365   v->u.rail.cached_tilt = train_can_tilt;
    00366
    00367   /* 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) */
    00368   TrainCargoChanged(v);
    00369
    00370   if (IsFrontEngine(v)) {
    00371     UpdateTrainAcceleration(v);
    00372     InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
    00373   }
    00374 }
    00375
    00376 enum AccelType {
    00377   AM_ACCEL,
    00378   AM_BRAKE
    00379 };
    00380
    00381 static bool TrainShouldStop(const Vehicle* v, TileIndex tile)
    00382 {
    00383   const Order* o = &v->current_order;
    00384   StationID sid = GetStationIndex(tile);
    00385
    00386   assert(v->type == VEH_TRAIN);
    00387   /* When does a train drive through a station
    00388    * first we deal with the "new nonstop handling" */
    00389   if (_patches.new_nonstop && o->flags & OFB_NON_STOP && sid == o->dest) {
    00390     return false;
    00391   }
    00392
    00393   if (v->last_station_visited == sid) return false;
    00394
    00395   if (sid != o->dest && (o->flags & OFB_NON_STOP || _patches.new_nonstop)) {
    00396     return false;
    00397   }
    00398
    00399   return true;
    00400 }
    00401
    00403 static int GetTrainAcceleration(Vehicle *v, bool mode)
    00404 {
    00405   static const int absolute_max_speed = 2000;
    00406   int max_speed = absolute_max_speed;
    00407   int speed = v->cur_speed * 10 / 16; // km-ish/h -> mp/h
    00408   int curvecount[2] = {0, 0};
    00409
    00410   /*first find the curve speed limit */
    00411   int numcurve = 0;
    00412   int sum = 0;
    00413   int pos = 0;
    00414   int lastpos = -1;
    00415   for (const Vehicle *u = v; u->Next() != NULL; u = u->Next(), pos++) {
    00416     Direction this_dir = u->direction;
    00417     Direction next_dir = u->Next()->direction;
    00418
    00419     DirDiff dirdiff = DirDifference(this_dir, next_dir);
    00420     if (dirdiff == DIRDIFF_SAME) continue;
    00421
    00422     if (dirdiff == DIRDIFF_45LEFT) curvecount[0]++;
    00423     if (dirdiff == DIRDIFF_45RIGHT) curvecount[1]++;
    00424     if (dirdiff == DIRDIFF_45LEFT || dirdiff == DIRDIFF_45RIGHT) {
    00425       if (lastpos != -1) {
    00426         numcurve++;
    00427         sum += pos - lastpos;
    00428         if (pos - lastpos == 1) {
    00429           max_speed = 88;
    00430         }
    00431       }
    00432       lastpos = pos;
    00433     }
    00434
    00435     /*if we have a 90 degree turn, fix the speed limit to 60 */
    00436     if (dirdiff == DIRDIFF_90LEFT || dirdiff == DIRDIFF_90RIGHT) {
    00437       max_speed = 61;
    00438     }
    00439   }
    00440
    00441   if ((curvecount[0] != 0 || curvecount[1] != 0) && max_speed > 88) {
    00442     int total = curvecount[0] + curvecount[1];
    00443
    00444     if (curvecount[0] == 1 && curvecount[1] == 1) {
    00445       max_speed = absolute_max_speed;
    00446     } else if (total > 1) {
    00447       if (numcurve > 0) sum /= numcurve;
    00448       max_speed = 232 - (13 - Clamp(sum, 1, 12)) * (13 - Clamp(sum, 1, 12));
    00449     }
    00450   }
    00451
    00452   if (max_speed != absolute_max_speed) {
    00453     /* Apply the engine's rail type curve speed advantage, if it slowed by curves */
    00454     const RailtypeInfo *rti = GetRailTypeInfo(v->u.rail.railtype);
    00455     max_speed += (max_speed / 2) * rti->curve_speed;
    00456
    00457     if (v->u.rail.cached_tilt) {
    00458       /* Apply max_speed bonus of 20% for a tilting train */
    00459       max_speed += max_speed / 5;
    00460     }
    00461   }
    00462
    00463   if (IsTileType(v->tile, MP_STATION) && IsFrontEngine(v)) {
    00464     if (TrainShouldStop(v, v->tile)) {
    00465       int station_length = GetStationByTile(v->tile)->GetPlatformLength(v->tile, DirToDiagDir(v->direction));
    00466
    00467       int st_max_speed = 120;
    00468
    00469       int delta_v = v->cur_speed / (station_length + 1);
    00470       if (v->max_speed > (v->cur_speed - delta_v)) {
    00471         st_max_speed = v->cur_speed - (delta_v / 10);
    00472       }
    00473
    00474       st_max_speed = max(st_max_speed, 25 * station_length);
    00475       max_speed = min(max_speed, st_max_speed);
    00476     }
    00477   }
    00478
    00479   int mass = v->u.rail.cached_weight;
    00480   int power = v->u.rail.cached_power * 746;
    00481   max_speed = min(max_speed, v->u.rail.cached_max_speed);
    00482
    00483   int num = 0; //number of vehicles, change this into the number of axles later
    00484   int incl = 0;
    00485   int drag_coeff = 20; //[1e-4]
    00486   for (const Vehicle *u = v; u != NULL; u = u->Next()) {
    00487     num++;
    00488     drag_coeff += 3;
    00489
    00490     if (u->u.rail.track == TRACK_BIT_DEPOT) max_speed = min(max_speed, 61);
    00491
    00492     if (HasBit(u->u.rail.flags, VRF_GOINGUP)) {
    00493       incl += u->u.rail.cached_veh_weight * 60; //3% slope, quite a bit actually
    00494     } else if (HasBit(u->u.rail.flags, VRF_GOINGDOWN)) {
    00495       incl -= u->u.rail.cached_veh_weight * 60;
    00496     }
    00497   }
    00498
    00499   v->max_speed = max_speed;
    00500
    00501   const int area = 120;
    00502   const int friction = 35; //[1e-3]
    00503   int resistance;
    00504   if (v->u.rail.railtype != RAILTYPE_MAGLEV) {
    00505     resistance = 13 * mass / 10;
    00506     resistance += 60 * num;
    00507     resistance += friction * mass * speed / 1000;
    00508     resistance += (area * drag_coeff * speed * speed) / 10000;
    00509   } else {
    00510     resistance = (area * (drag_coeff / 2) * speed * speed) / 10000;
    00511   }
    00512   resistance += incl;
    00513   resistance *= 4; //[N]
    00514
    00515   /* Due to the mph to m/s conversion below, at speeds below 3 mph the force is
    00516    * actually double the train's power */
    00517   const int max_te = v->u.rail.cached_max_te; // [N]
    00518   int force;
    00519   if (speed > 2) {
    00520     switch (v->u.rail.railtype) {
    00521       case RAILTYPE_RAIL:
    00522       case RAILTYPE_ELECTRIC:
    00523       case RAILTYPE_MONO:
    00524         force = power / speed; //[N]
    00525         force *= 22;
    00526         force /= 10;
    00527         if (mode == AM_ACCEL && force > max_te) force = max_te;
    00528         break;
    00529
    00530       default: NOT_REACHED();
    00531       case RAILTYPE_MAGLEV:
    00532         force = power / 25;
    00533         break;
    00534     }
    00535   } else {
    00536     /* "kickoff" acceleration */
    00537     force = (mode == AM_ACCEL && v->u.rail.railtype != RAILTYPE_MAGLEV) ? min(max_te, power) : power;
    00538     force = max(force, (mass * 8) + resistance);
    00539   }
    00540
    00541   if (force <= 0) force = 10000;
    00542
    00543   if (v->u.rail.railtype != RAILTYPE_MAGLEV) force = min(force, mass * 10 * 200);
    00544
    00545   if (mode == AM_ACCEL) {
    00546     return (force - resistance) / (mass * 4);
    00547   } else {
    00548     return min((-force - resistance) / (mass * 4), -10000 / (mass * 4));
    00549   }
    00550 }
    00551
    00552 void UpdateTrainAcceleration(Vehicle* v)
    00553 {
    00554   assert(IsFrontEngine(v));
    00555
    00556   v->max_speed = v->u.rail.cached_max_speed;
    00557
    00558   uint power = v->u.rail.cached_power;
    00559   uint weight = v->u.rail.cached_weight;
    00560   assert(weight != 0);
    00561   v->acceleration = Clamp(power / weight * 4, 1, 255);
    00562 }
    00563
    00564 int Train::GetImage(Direction direction) const
    00565 {
    00566   int img = this->spritenum;
    00567   int base;
    00568
    00569   if (HasBit(this->u.rail.flags, VRF_REVERSE_DIRECTION)) direction = ReverseDir(direction);
    00570
    00571   if (is_custom_sprite(img)) {
    00572     base = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(img)));
    00573     if (base != 0) return base;
    00574     img = _orig_rail_vehicle_info[this->engine_type].image_index;
    00575   }
    00576
    00577   base = _engine_sprite_base[img] + ((direction + _engine_sprite_add[img]) & _engine_sprite_and[img]);
    00578
    00579   if (this->cargo.Count() >= this->cargo_cap / 2U) base += _wagon_full_adder[img];
    00580   return base;
    00581 }
    00582
    00583 void DrawTrainEngine(int x, int y, EngineID engine, SpriteID pal)
    00584 {
    00585   const RailVehicleInfo *rvi = RailVehInfo(engine);
    00586
    00587   int img = rvi->image_index;
    00588   SpriteID image = 0;
    00589
    00590   if (is_custom_sprite(img)) {
    00591     image = GetCustomVehicleIcon(engine, DIR_W);
    00592     if (image == 0) {
    00593       img = _orig_rail_vehicle_info[engine].image_index;
    00594     } else {
    00595       y += _traininfo_vehicle_pitch;
    00596     }
    00597   }
    00598   if (image == 0) {
    00599     image = (6 & _engine_sprite_and[img]) + _engine_sprite_base[img];
    00600   }
    00601
    00602   if (rvi->railveh_type == RAILVEH_MULTIHEAD) {
    00603     DrawSprite(image, pal, x - 14, y);
    00604     x += 15;
    00605     image = 0;
    00606     if (is_custom_sprite(img)) {
    00607       image = GetCustomVehicleIcon(engine, DIR_E);
    00608       if (image == 0) img = _orig_rail_vehicle_info[engine].image_index;
    00609     }
    00610     if (image == 0) {
    00611       image =
    00612         ((6 + _engine_sprite_add[img + 1]) & _engine_sprite_and[img + 1]) +
    00613         _engine_sprite_base[img + 1];
    00614     }
    00615   }
    00616   DrawSprite(image, pal, x, y);
    00617 }
    00618
    00619 static CommandCost CmdBuildRailWagon(EngineID engine, TileIndex tile, uint32 flags)
    00620 {
    00621   const RailVehicleInfo *rvi = RailVehInfo(engine);
    00622   CommandCost value(EXPENSES_NEW_VEHICLES, (GetEngineProperty(engine, 0x17, rvi->base_cost) * _price.build_railwagon) >> 8);
    00623
    00624   uint num_vehicles = 1 + CountArticulatedParts(engine, false);
    00625
    00626   if (!(flags & DC_QUERY_COST)) {
    00627     /* Allow for the wagon and the articulated parts, plus one to "terminate" the list. */
    00628     Vehicle **vl = (Vehicle**)alloca(sizeof(*vl) * (num_vehicles + 1));
    00629     memset(vl, 0, sizeof(*vl) * (num_vehicles + 1));
    00630
    00631     if (!Vehicle::AllocateList(vl, num_vehicles))
    00632       return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
    00633
    00634     if (flags & DC_EXEC) {
    00635       Vehicle *v = vl[0];
    00636       v->spritenum = rvi->image_index;
    00637
    00638       Vehicle *u = NULL;
    00639
    00640       Vehicle *w;
    00641       FOR_ALL_VEHICLES(w) {
    00642         if (w->type == VEH_TRAIN && w->tile == tile &&
    00643             IsFreeWagon(w) && w->engine_type == engine &&
    00644             !HASBITS(w->vehstatus, VS_CRASHED)) {
    00645           u = GetLastVehicleInChain(w);
    00646           break;
    00647         }
    00648       }
    00649
    00650       v = new (v) Train();
    00651       v->engine_type = engine;
    00652
    00653       DiagDirection dir = GetRailDepotDirection(tile);
    00654
    00655       v->direction = DiagDirToDir(dir);
    00656       v->tile = tile;
    00657
    00658       int x = TileX(tile) * TILE_SIZE | _vehicle_initial_x_fract[dir];
    00659       int y = TileY(tile) * TILE_SIZE | _vehicle_initial_y_fract[dir];
    00660
    00661       v->x_pos = x;
    00662       v->y_pos = y;
    00663       v->z_pos = GetSlopeZ(x, y);
    00664       v->owner = _current_player;
    00665       v->u.rail.track = TRACK_BIT_DEPOT;
    00666       v->vehstatus = VS_HIDDEN | VS_DEFPAL;
    00667
    00668       v->subtype = 0;
    00669       SetTrainWagon(v);
    00670
    00671       if (u != NULL) {
    00672         u->SetNext(v);
    00673       } else {
    00674         SetFreeWagon(v);
    00675         InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
    00676       }
    00677
    00678       v->cargo_type = rvi->cargo_type;
    00679       v->cargo_subtype = 0;
    00680       v->cargo_cap = rvi->capacity;
    00681       v->value = value.GetCost();
    00682 //      v->day_counter = 0;
    00683
    00684       v->u.rail.railtype = rvi->railtype;
    00685
    00686       v->build_year = _cur_year;
    00687       v->cur_image = 0xAC2;
    00688       v->random_bits = VehicleRandomBits();
    00689
    00690       v->group_id = DEFAULT_GROUP;
    00691
    00692       AddArticulatedParts(vl, VEH_TRAIN);
    00693
    00694       _new_vehicle_id = v->index;
    00695
    00696       VehiclePositionChanged(v);
    00697       TrainConsistChanged(v->First(), false);
    00698       UpdateTrainGroupID(v->First());
    00699
    00700       InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
    00701       if (IsLocalPlayer()) {
    00702         InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Train window
    00703       }
    00704       GetPlayer(_current_player)->num_engines[engine]++;
    00705     }
    00706   }
    00707
    00708   return value;
    00709 }
    00710
    00712 static void NormalizeTrainVehInDepot(const Vehicle* u)
    00713 {
    00714   const Vehicle* v;
    00715
    00716   FOR_ALL_VEHICLES(v) {
    00717     if (v->type == VEH_TRAIN && IsFreeWagon(v) &&
    00718         v->tile == u->tile &&
    00719         v->u.rail.track == TRACK_BIT_DEPOT) {
    00720       if (CmdFailed(DoCommand(0, v->index | (u->index << 16), 1, DC_EXEC,
    00721           CMD_MOVE_RAIL_VEHICLE)))
    00722         break;
    00723     }
    00724   }
    00725 }
    00726
    00727 static CommandCost EstimateTrainCost(EngineID engine, const RailVehicleInfo* rvi)
    00728 {
    00729   return CommandCost(EXPENSES_NEW_VEHICLES, GetEngineProperty(engine, 0x17, rvi->base_cost) * (_price.build_railvehicle >> 3) >> 5);
    00730 }
    00731
    00732 static void AddRearEngineToMultiheadedTrain(Vehicle* v, Vehicle* u, bool building)
    00733 {
    00734   u = new (u) Train();
    00735   u->direction = v->direction;
    00736   u->owner = v->owner;
    00737   u->tile = v->tile;
    00738   u->x_pos = v->x_pos;
    00739   u->y_pos = v->y_pos;
    00740   u->z_pos = v->z_pos;
    00741   u->u.rail.track = TRACK_BIT_DEPOT;
    00742   u->vehstatus = v->vehstatus & ~VS_STOPPED;
    00743   u->subtype = 0;
    00744   SetMultiheaded(u);
    00745   u->spritenum = v->spritenum + 1;
    00746   u->cargo_type = v->cargo_type;
    00747   u->cargo_subtype = v->cargo_subtype;
    00748   u->cargo_cap = v->cargo_cap;
    00749   u->u.rail.railtype = v->u.rail.railtype;
    00750   if (building) v->SetNext(u);
    00751   u->engine_type = v->engine_type;
    00752   u->build_year = v->build_year;
    00753   if (building) v->value >>= 1;
    00754   u->value = v->value;
    00755   u->cur_image = 0xAC2;
    00756   u->random_bits = VehicleRandomBits();
    00757   VehiclePositionChanged(u);
    00758 }
    00759
    00766 CommandCost CmdBuildRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    00767 {
    00768   /* Check if the engine-type is valid (for the player) */
    00769   if (!IsEngineBuildable(p1, VEH_TRAIN, _current_player)) return_cmd_error(STR_RAIL_VEHICLE_NOT_AVAILABLE);
    00770
    00771   /* Check if the train is actually being built in a depot belonging
    00772    * to the player. Doesn't matter if only the cost is queried */
    00773   if (!(flags & DC_QUERY_COST)) {
    00774     if (!IsTileDepotType(tile, TRANSPORT_RAIL)) return CMD_ERROR;
    00775     if (!IsTileOwner(tile, _current_player)) return CMD_ERROR;
    00776   }
    00777
    00778   const RailVehicleInfo *rvi = RailVehInfo(p1);
    00779
    00780   /* Check if depot and new engine uses the same kind of tracks */
    00781   /* We need to see if the engine got power on the tile to avoid eletric engines in non-electric depots */
    00782   if (!HasPowerOnRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR;
    00783
    00784   if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildRailWagon(p1, tile, flags);
    00785
    00786   CommandCost value = EstimateTrainCost(p1, rvi);
    00787
    00788   uint num_vehicles =
    00789     (rvi->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1) +
    00790     CountArticulatedParts(p1, false);
    00791
    00792   if (!(flags & DC_QUERY_COST)) {
    00793     /* Allow for the dual-heads and the articulated parts, plus one to "terminate" the list. */
    00794     Vehicle **vl = (Vehicle**)alloca(sizeof(*vl) * (num_vehicles + 1));
    00795     memset(vl, 0, sizeof(*vl) * (num_vehicles + 1));
    00796
    00797     if (!Vehicle::AllocateList(vl, num_vehicles))
    00798       return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
    00799
    00800     Vehicle *v = vl[0];
    00801
    00802     UnitID unit_num = (flags & DC_AUTOREPLACE) ? 0 : GetFreeUnitNumber(VEH_TRAIN);
    00803     if (unit_num > _patches.max_trains)
    00804       return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
    00805
    00806     if (flags & DC_EXEC) {
    00807       DiagDirection dir = GetRailDepotDirection(tile);
    00808       int x = TileX(tile) * TILE_SIZE + _vehicle_initial_x_fract[dir];
    00809       int y = TileY(tile) * TILE_SIZE + _vehicle_initial_y_fract[dir];
    00810
    00811       v = new (v) Train();
    00812       v->unitnumber = unit_num;
    00813       v->direction = DiagDirToDir(dir);
    00814       v->tile = tile;
    00815       v->owner = _current_player;
    00816       v->x_pos = x;
    00817       v->y_pos = y;
    00818       v->z_pos = GetSlopeZ(x, y);
    00819       v->running_ticks = 0;
    00820       v->u.rail.track = TRACK_BIT_DEPOT;
    00821       v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
    00822       v->spritenum = rvi->image_index;
    00823       v->cargo_type = rvi->cargo_type;
    00824       v->cargo_subtype = 0;
    00825       v->cargo_cap = rvi->capacity;
    00826       v->max_speed = rvi->max_speed;
    00827       v->value = value.GetCost();
    00828       v->last_station_visited = INVALID_STATION;
    00829       v->dest_tile = 0;
    00830
    00831       v->engine_type = p1;
    00832
    00833       const Engine *e = GetEngine(p1);
    00834       v->reliability = e->reliability;
    00835       v->reliability_spd_dec = e->reliability_spd_dec;
    00836       v->max_age = e->lifelength * 366;
    00837
    00838       v->name = NULL;
    00839       v->u.rail.railtype = rvi->railtype;
    00840       _new_vehicle_id = v->index;
    00841
    00842       v->service_interval = _patches.servint_trains;
    00843       v->date_of_last_service = _date;
    00844       v->build_year = _cur_year;
    00845       v->cur_image = 0xAC2;
    00846       v->random_bits = VehicleRandomBits();
    00847
    00848       v->vehicle_flags = 0;
    00849       if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
    00850
    00851       v->group_id = DEFAULT_GROUP;
    00852
    00853       v->subtype = 0;
    00854       SetFrontEngine(v);
    00855       SetTrainEngine(v);
    00856
    00857       VehiclePositionChanged(v);
    00858
    00859       if (rvi->railveh_type == RAILVEH_MULTIHEAD) {
    00860         SetMultiheaded(v);
    00861         AddRearEngineToMultiheadedTrain(vl[0], vl[1], true);
    00862         /* Now we need to link the front and rear engines together
    00863          * other_multiheaded_part is the pointer that links to the other half of the engine
    00864          * vl[0] is the front and vl[1] is the rear
    00865          */
    00866         vl[0]->u.rail.other_multiheaded_part = vl[1];
    00867         vl[1]->u.rail.other_multiheaded_part = vl[0];
    00868       } else {
    00869         AddArticulatedParts(vl, VEH_TRAIN);
    00870       }
    00871
    00872       TrainConsistChanged(v, false);
    00873       UpdateTrainGroupID(v);
    00874
    00875       if (!HasBit(p2, 1) && !(flags & DC_AUTOREPLACE)) { // check if the cars should be added to the new vehicle
    00876         NormalizeTrainVehInDepot(v);
    00877       }
    00878
    00879       InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
    00880       RebuildVehicleLists();
    00881       InvalidateWindow(WC_COMPANY, v->owner);
    00882       if (IsLocalPlayer())
    00883         InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Train window
    00884
    00885       GetPlayer(_current_player)->num_engines[p1]++;
    00886     }
    00887   }
    00888
    00889   return value;
    00890 }
    00891
    00892
    00893 /* Check if all the wagons of the given train are in a depot, returns the
    00894  * number of cars (including loco) then. If not it returns -1 */
    00895 int CheckTrainInDepot(const Vehicle *v, bool needs_to_be_stopped)
    00896 {
    00897   TileIndex tile = v->tile;
    00898
    00899   /* check if stopped in a depot */
    00900   if (!IsTileDepotType(tile, TRANSPORT_RAIL) || v->cur_speed != 0) return -1;
    00901
    00902   int count = 0;
    00903   for (; v != NULL; v = v->Next()) {
    00904     /* This count is used by the depot code to determine the number of engines
    00905      * in the consist. Exclude articulated parts so that autoreplacing to
    00906      * engines with more articulated parts than before works correctly.
    00907      *
    00908      * Also skip counting rear ends of multiheaded engines */
    00909     if (!IsArticulatedPart(v) && !IsRearDualheaded(v)) count++;
    00910     if (v->u.rail.track != TRACK_BIT_DEPOT || v->tile != tile ||
    00911         (IsFrontEngine(v) && needs_to_be_stopped && !(v->vehstatus & VS_STOPPED))) {
    00912       return -1;
    00913     }
    00914   }
    00915
    00916   return count;
    00917 }
    00918
    00919 /* Used to check if the train is inside the depot and verifying that the VS_STOPPED flag is set */
    00920 int CheckTrainStoppedInDepot(const Vehicle *v)
    00921 {
    00922   return CheckTrainInDepot(v, true);
    00923 }
    00924
    00925 /* Used to check if the train is inside the depot, but not checking the VS_STOPPED flag */
    00926 inline bool CheckTrainIsInsideDepot(const Vehicle *v)
    00927 {
    00928   return CheckTrainInDepot(v, false) > 0;
    00929 }
    00930
    00937 static Vehicle *UnlinkWagon(Vehicle *v, Vehicle *first)
    00938 {
    00939   /* unlinking the first vehicle of the chain? */
    00940   if (v == first) {
    00941     v = GetNextVehicle(v);
    00942     if (v == NULL) return NULL;
    00943
    00944     if (IsTrainWagon(v)) SetFreeWagon(v);
    00945
    00946     return v;
    00947   }
    00948
    00949   Vehicle *u;
    00950   for (u = first; GetNextVehicle(u) != v; u = GetNextVehicle(u)) {}
    00951   GetLastEnginePart(u)->SetNext(GetNextVehicle(v));
    00952   return first;
    00953 }
    00954
    00955 static Vehicle *FindGoodVehiclePos(const Vehicle *src)
    00956 {
    00957   Vehicle *dst;
    00958   EngineID eng = src->engine_type;
    00959   TileIndex tile = src->tile;
    00960
    00961   FOR_ALL_VEHICLES(dst) {
    00962     if (dst->type == VEH_TRAIN && IsFreeWagon(dst) && dst->tile == tile && !HASBITS(dst->vehstatus, VS_CRASHED)) {
    00963       /* check so all vehicles in the line have the same engine. */
    00964       Vehicle *v = dst;
    00965
    00966       while (v->engine_type == eng) {
    00967         v = v->Next();
    00968         if (v == NULL) return dst;
    00969       }
    00970     }
    00971   }
    00972
    00973   return NULL;
    00974 }
    00975
    00976 /*
    00977  * add a vehicle v behind vehicle dest
    00978  * use this function since it sets flags as needed
    00979  */
    00980 static void AddWagonToConsist(Vehicle *v, Vehicle *dest)
    00981 {
    00982   UnlinkWagon(v, v->First());
    00983   if (dest == NULL) return;
    00984
    00985   Vehicle *next = dest->Next();
    00986   v->SetNext(NULL);
    00987   dest->SetNext(v);
    00988   v->SetNext(next);
    00989   ClearFreeWagon(v);
    00990   ClearFrontEngine(v);
    00991 }
    00992
    00993 /*
    00994  * move around on the train so rear engines are placed correctly according to the other engines
    00995  * always call with the front engine
    00996  */
    00997 static void NormaliseTrainConsist(Vehicle *v)
    00998 {
    00999   if (IsFreeWagon(v)) return;
    01000
    01001   assert(IsFrontEngine(v));
    01002
    01003   for (; v != NULL; v = GetNextVehicle(v)) {
    01004     if (!IsMultiheaded(v) || !IsTrainEngine(v)) continue;
    01005
    01006     /* make sure that there are no free cars before next engine */
    01007     Vehicle *u;
    01008     for (u = v; u->Next() != NULL && !IsTrainEngine(u->Next()); u = u->Next()) {}
    01009
    01010     if (u == v->u.rail.other_multiheaded_part) continue;
    01011     AddWagonToConsist(v->u.rail.other_multiheaded_part, u);
    01012   }
    01013 }
    01014
    01023 CommandCost CmdMoveRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    01024 {
    01025   VehicleID s = GB(p1, 0, 16);
    01026   VehicleID d = GB(p1, 16, 16);
    01027
    01028   if (!IsValidVehicleID(s)) return CMD_ERROR;
    01029
    01030   Vehicle *src = GetVehicle(s);
    01031
    01032   if (src->type != VEH_TRAIN || !CheckOwnership(src->owner)) return CMD_ERROR;
    01033
    01034   /* Do not allow moving crashed vehicles inside the depot, it is likely to cause asserts later */
    01035   if (HASBITS(src->vehstatus, VS_CRASHED)) return CMD_ERROR;
    01036
    01037   /* if nothing is selected as destination, try and find a matching vehicle to drag to. */
    01038   Vehicle *dst;
    01039   if (d == INVALID_VEHICLE) {
    01040     dst = IsTrainEngine(src) ? NULL : FindGoodVehiclePos(src);
    01041   } else {
    01042     if (!IsValidVehicleID(d)) return CMD_ERROR;
    01043     dst = GetVehicle(d);
    01044     if (dst->type != VEH_TRAIN || !CheckOwnership(dst->owner)) return CMD_ERROR;
    01045
    01046     /* Do not allow appending to crashed vehicles, too */
    01047     if (HASBITS(dst->vehstatus, VS_CRASHED)) return CMD_ERROR;
    01048   }
    01049
    01050   /* if an articulated part is being handled, deal with its parent vehicle */
    01051   while (IsArticulatedPart(src)) src = src->Previous();
    01052   if (dst != NULL) {
    01053     while (IsArticulatedPart(dst)) dst = dst->Previous();
    01054   }
    01055
    01056   /* don't move the same vehicle.. */
    01057   if (src == dst) return CommandCost();
    01058
    01059   /* locate the head of the two chains */
    01060   Vehicle *src_head = src->First();
    01061   Vehicle *dst_head;
    01062   if (dst != NULL) {
    01063     dst_head = dst->First();
    01064     if (dst_head->tile != src_head->tile) return CMD_ERROR;
    01065     /* Now deal with articulated part of destination wagon */
    01066     dst = GetLastEnginePart(dst);
    01067   } else {
    01068     dst_head = NULL;
    01069   }
    01070
    01071   if (IsRearDualheaded(src)) return_cmd_error(STR_REAR_ENGINE_FOLLOW_FRONT_ERROR);
    01072
    01073   /* when moving all wagons, we can't have the same src_head and dst_head */
    01074   if (HasBit(p2, 0) && src_head == dst_head) return CommandCost();
    01075
    01076   {
    01077     int max_len = _patches.mammoth_trains ? 100 : 10;
    01078
    01079     /* check if all vehicles in the source train are stopped inside a depot. */
    01080     int src_len = CheckTrainStoppedInDepot(src_head);
    01081     if (src_len < 0) return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
    01082
    01083     /* check the destination row if the source and destination aren't the same. */
    01084     if (src_head != dst_head) {
    01085       int dst_len = 0;
    01086
    01087       if (dst_head != NULL) {
    01088         /* check if all vehicles in the dest train are stopped. */
    01089         dst_len = CheckTrainStoppedInDepot(dst_head);
    01090         if (dst_len < 0) return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
    01091       }
    01092
    01093       /* We are moving between rows, so only count the wagons from the source
    01094        * row that are being moved. */
    01095       if (HasBit(p2, 0)) {
    01096         const Vehicle *u;
    01097         for (u = src_head; u != src && u != NULL; u = GetNextVehicle(u))
    01098           src_len--;
    01099       } else {
    01100         /* If moving only one vehicle, just count that. */
    01101         src_len = 1;
    01102       }
    01103
    01104       if (src_len + dst_len > max_len) {
    01105         /* Abort if we're adding too many wagons to a train. */
    01106         if (dst_head != NULL && IsFrontEngine(dst_head)) return_cmd_error(STR_8819_TRAIN_TOO_LONG);
    01107         /* Abort if we're making a train on a new row. */
    01108         if (dst_head == NULL && IsTrainEngine(src)) return_cmd_error(STR_8819_TRAIN_TOO_LONG);
    01109       }
    01110     } else {
    01111       /* Abort if we're creating a new train on an existing row. */
    01112       if (src_len > max_len && src == src_head && IsTrainEngine(GetNextVehicle(src_head)))
    01113         return_cmd_error(STR_8819_TRAIN_TOO_LONG);
    01114     }
    01115   }
    01116
    01117   /* moving a loco to a new line?, then we need to assign a unitnumber. */
    01118   if (dst == NULL && !IsFrontEngine(src) && IsTrainEngine(src)) {
    01119     UnitID unit_num = GetFreeUnitNumber(VEH_TRAIN);
    01120     if (unit_num > _patches.max_trains)
    01121       return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
    01122
    01123     if (flags & DC_EXEC) src->unitnumber = unit_num;
    01124   }
    01125
    01126   /* When we move the front vehicle, the second vehicle might need a unitnumber */
    01127   if (!HasBit(p2, 0) && (IsFreeWagon(src) || IsFrontEngine(src)) && (flags & DC_AUTOREPLACE) == 0) {
    01128     Vehicle *second = GetNextUnit(src);
    01129     if (second != NULL && IsTrainEngine(second) && GetFreeUnitNumber(VEH_TRAIN) > _patches.max_trains) {
    01130       return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
    01131     }
    01132   }
    01133
    01134   /*
    01135    * Check whether the vehicles in the source chain are in the destination
    01136    * chain. This can easily be done by checking whether the first vehicle
    01137    * of the source chain is in the destination chain as the Next/Previous
    01138    * pointers always make a doubly linked list of it where the assumption
    01139    * v->Next()->Previous() == v holds (assuming v->Next() != NULL).
    01140    */
    01141   bool src_in_dst = false;
    01142   for (Vehicle *v = dst_head; !src_in_dst && v != NULL; v = v->Next()) src_in_dst = v == src;
    01143
    01144   /*
    01145    * If the source chain is in the destination chain then the user is
    01146    * only reordering the vehicles, thus not attaching a new vehicle.
    01147    * Therefor the 'allow wagon attach' callback does not need to be
    01148    * called. If it would be called strange things would happen because
    01149    * one 'attaches' an already 'attached' vehicle causing more trouble
    01150    * than it actually solves (infinite loops and such).
    01151    */
    01152   if (dst_head != NULL && !src_in_dst) {
    01153     /*
    01154      * When performing the 'allow wagon attach' callback, we have to check
    01155      * that for each and every wagon, not only the first one. This means
    01156      * that we have to test one wagon, attach it to the train and then test
    01157      * the next wagon till we have reached the end. We have to restore it
    01158      * to the state it was before we 'tried' attaching the train when the
    01159      * attaching fails or succeeds because we are not 'only' doing this
    01160      * in the DC_EXEC state.
    01161      */
    01162     Vehicle *dst_tail = dst_head;
    01163     while (dst_tail->Next() != NULL) dst_tail = dst_tail->Next();
    01164
    01165     Vehicle *orig_tail = dst_tail;
    01166     Vehicle *next_to_attach = src;
    01167     Vehicle *src_previous = src->Previous();
    01168
    01169     while (next_to_attach != NULL) {
    01170       /* Back up and clear the first_engine data to avoid using wagon override group */
    01171       EngineID first_engine = next_to_attach->u.rail.first_engine;
    01172       next_to_attach->u.rail.first_engine = INVALID_ENGINE;
    01173
    01174       uint16 callback = GetVehicleCallbackParent(CBID_TRAIN_ALLOW_WAGON_ATTACH, 0, 0, dst_head->engine_type, next_to_attach, dst_head);
    01175
    01176       /* Restore original first_engine data */
    01177       next_to_attach->u.rail.first_engine = first_engine;
    01178
    01179       if (callback != CALLBACK_FAILED) {
    01180         StringID error = STR_NULL;
    01181
    01182         if (callback == 0xFD) error = STR_INCOMPATIBLE_RAIL_TYPES;
    01183         if (callback < 0xFD) error = GetGRFStringID(GetEngineGRFID(dst_head->engine_type), 0xD000 + callback);
    01184
    01185         if (error != STR_NULL) {
    01186           /*
    01187            * The attaching is not allowed. In this case 'next_to_attach'
    01188            * can contain some vehicles of the 'source' and the destination
    01189            * train can have some too. We 'just' add the to-be added wagons
    01190            * to the chain and then split it where it was previously
    01191            * separated, i.e. the tail of the original destination train.
    01192            * Furthermore the 'previous' link of the original source vehicle needs
    01193            * to be restored, otherwise the train goes missing in the depot.
    01194            */
    01195           dst_tail->SetNext(next_to_attach);
    01196           orig_tail->SetNext(NULL);
    01197           if (src_previous != NULL) src_previous->SetNext(src);
    01198
    01199           return_cmd_error(error);
    01200         }
    01201       }
    01202
    01203       /* Only check further wagons if told to move the chain */
    01204       if (!HasBit(p2, 0)) break;
    01205
    01206       /*
    01207        * Adding a next wagon to the chain so we can test the other wagons.
    01208        * First 'take' the first wagon from 'next_to_attach' and move it
    01209        * to the next wagon. Then add that to the tail of the destination
    01210        * train and update the tail with the new vehicle.
    01211        */
    01212       Vehicle *to_add = next_to_attach;
    01213       next_to_attach = next_to_attach->Next();
    01214
    01215       to_add->SetNext(NULL);
    01216       dst_tail->SetNext(to_add);
    01217       dst_tail = dst_tail->Next();
    01218     }
    01219
    01220     /*
    01221      * When we reach this the attaching is allowed. It also means that the
    01222      * chain of vehicles to attach is empty, so we do not need to merge that.
    01223      * This means only the splitting needs to be done.
    01224      * Furthermore the 'previous' link of the original source vehicle needs
    01225      * to be restored, otherwise the train goes missing in the depot.
    01226      */
    01227     orig_tail->SetNext(NULL);
    01228     if (src_previous != NULL) src_previous->SetNext(src);
    01229   }
    01230
    01231   /* do it? */
    01232   if (flags & DC_EXEC) {
    01233     /* If we move the front Engine and if the second vehicle is not an engine
    01234        add the whole vehicle to the DEFAULT_GROUP */
    01235     if (IsFrontEngine(src) && !IsDefaultGroupID(src->group_id)) {
    01236       Vehicle *v = GetNextVehicle(src);
    01237
    01238       if (v != NULL && IsTrainEngine(v)) {
    01239         v->group_id   = src->group_id;
    01240         src->group_id = DEFAULT_GROUP;
    01241       }
    01242     }
    01243
    01244     if (HasBit(p2, 0)) {
    01245       /* unlink ALL wagons */
    01246       if (src != src_head) {
    01247         Vehicle *v = src_head;
    01248         while (GetNextVehicle(v) != src) v = GetNextVehicle(v);
    01249         GetLastEnginePart(v)->SetNext(NULL);
    01250       } else {
    01251         InvalidateWindowData(WC_VEHICLE_DEPOT, src_head->tile); // We removed a line
    01252         src_head = NULL;
    01253       }
    01254     } else {
    01255       /* if moving within the same chain, dont use dst_head as it may get invalidated */
    01256       if (src_head == dst_head) dst_head = NULL;
    01257       /* unlink single wagon from linked list */
    01258       src_head = UnlinkWagon(src, src_head);
    01259       GetLastEnginePart(src)->SetNext(NULL);
    01260     }
    01261
    01262     if (dst == NULL) {
    01263       /* We make a new line in the depot, so we know already that we invalidate the window data */
    01264       InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile);
    01265
    01266       /* move the train to an empty line. for locomotives, we set the type to TS_Front. for wagons, 4. */
    01267       if (IsTrainEngine(src)) {
    01268         if (!IsFrontEngine(src)) {
    01269           /* setting the type to 0 also involves setting up the orders field. */
    01270           SetFrontEngine(src);
    01271           assert(src->orders == NULL);
    01272           src->num_orders = 0;
    01273
    01274           // Decrease the engines number of the src engine_type
    01275           if (!IsDefaultGroupID(src->group_id) && IsValidGroupID(src->group_id)) {
    01276             GetGroup(src->group_id)->num_engines[src->engine_type]--;
    01277           }
    01278
    01279           // If we move an engine to a new line affect it to the DEFAULT_GROUP
    01280           src->group_id = DEFAULT_GROUP;
    01281         }
    01282       } else {
    01283         SetFreeWagon(src);
    01284       }
    01285       dst_head = src;
    01286     } else {
    01287       if (IsFrontEngine(src)) {
    01288         /* the vehicle was previously a loco. need to free the order list and delete vehicle windows etc. */
    01289         DeleteWindowById(WC_VEHICLE_VIEW, src->index);
    01290         DeleteVehicleOrders(src);
    01291         RemoveVehicleFromGroup(src);
    01292       }
    01293
    01294       if (IsFrontEngine(src) || IsFreeWagon(src)) {
    01295         InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile);
    01296         ClearFrontEngine(src);
    01297         ClearFreeWagon(src);
    01298         src->unitnumber = 0; // doesn't occupy a unitnumber anymore.
    01299       }
    01300
    01301       /* link in the wagon(s) in the chain. */
    01302       {
    01303         Vehicle *v;
    01304
    01305         for (v = src; GetNextVehicle(v) != NULL; v = GetNextVehicle(v)) {}
    01306         GetLastEnginePart(v)->SetNext(dst->Next());
    01307       }
    01308       dst->SetNext(src);
    01309     }
    01310
    01311     if (src->u.rail.other_multiheaded_part != NULL) {
    01312       if (src->u.rail.other_multiheaded_part == src_head) {
    01313         src_head = src_head->Next();
    01314       }
    01315       AddWagonToConsist(src->u.rail.other_multiheaded_part, src);
    01316     }
    01317
    01318     /* If there is an engine behind first_engine we moved away, it should become new first_engine
    01319      * To do this, CmdMoveRailVehicle must be called once more
    01320      * we can't loop forever here because next time we reach this line we will have a front engine */
    01321     if (src_head != NULL && !IsFrontEngine(src_head) && IsTrainEngine(src_head)) {
    01322       /* As in CmdMoveRailVehicle src_head->group_id will be equal to DEFAULT_GROUP
    01323        * we need to save the group and reaffect it to src_head */
    01324       const GroupID tmp_g = src_head->group_id;
    01325       CmdMoveRailVehicle(0, flags, src_head->index | (INVALID_VEHICLE << 16), 1);
    01326       SetTrainGroupID(src_head, tmp_g);
    01327       src_head = NULL; // don't do anything more to this train since the new call will do it
    01328     }
    01329
    01330     if (src_head != NULL) {
    01331       NormaliseTrainConsist(src_head);
    01332       TrainConsistChanged(src_head, false);
    01333       UpdateTrainGroupID(src_head);
    01334       if (IsFrontEngine(src_head)) {
    01335         /* Update the refit button and window */
    01336         InvalidateWindow(WC_VEHICLE_REFIT, src_head->index);
    01337         InvalidateWindowWidget(WC_VEHICLE_VIEW, src_head->index, VVW_WIDGET_REFIT_VEH);
    01338       }
    01339       /* Update the depot window */
    01340       InvalidateWindow(WC_VEHICLE_DEPOT, src_head->tile);
    01341     }
    01342
    01343     if (dst_head != NULL) {
    01344       NormaliseTrainConsist(dst_head);
    01345       TrainConsistChanged(dst_head, false);
    01346       UpdateTrainGroupID(dst_head);
    01347       if (IsFrontEngine(dst_head)) {
    01348         /* Update the refit button and window */
    01349         InvalidateWindowWidget(WC_VEHICLE_VIEW, dst_head->index, VVW_WIDGET_REFIT_VEH);
    01350         InvalidateWindow(WC_VEHICLE_REFIT, dst_head->index);
    01351       }
    01352       /* Update the depot window */
    01353       InvalidateWindow(WC_VEHICLE_DEPOT, dst_head->tile);
    01354     }
    01355
    01356     RebuildVehicleLists();
    01357   }
    01358
    01359   return CommandCost();
    01360 }
    01361
    01368 CommandCost CmdStartStopTrain(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    01369 {
    01370   if (!IsValidVehicleID(p1)) return CMD_ERROR;
    01371
    01372   Vehicle *v = GetVehicle(p1);
    01373
    01374   if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR;
    01375
    01376   /* Check if this train can be started/stopped. The callback will fail or
    01377    * return 0xFF if it can. */
    01378   uint16 callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v);
    01379   if (callback != CALLBACK_FAILED && GB(callback, 0, 8) != 0xFF) {
    01380     StringID error = GetGRFStringID(GetEngineGRFID(v->engine_type), 0xD000 + callback);
    01381     return_cmd_error(error);
    01382   }
    01383
    01384   if (v->vehstatus & VS_STOPPED && v->u.rail.cached_power == 0) return_cmd_error(STR_TRAIN_START_NO_CATENARY);
    01385
    01386   if (flags & DC_EXEC) {
    01387     if (v->vehstatus & VS_STOPPED && v->u.rail.track == TRACK_BIT_DEPOT) {
    01388       DeleteVehicleNews(p1, STR_8814_TRAIN_IS_WAITING_IN_DEPOT);
    01389     }
    01390
    01391     v->vehstatus ^= VS_STOPPED;
    01392     InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
    01393     InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
    01394   }
    01395   return CommandCost();
    01396 }
    01397
    01409 CommandCost CmdSellRailWagon(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    01410 {
    01411   /* Check if we deleted a vehicle window */
    01412   Window *w = NULL;
    01413
    01414   if (!IsValidVehicleID(p1) || p2 > 2) return CMD_ERROR;
    01415
    01416   Vehicle *v = GetVehicle(p1);
    01417
    01418   if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR;
    01419
    01420   if (HASBITS(v->vehstatus, VS_CRASHED)) return_cmd_error(STR_CAN_T_SELL_DESTROYED_VEHICLE);
    01421
    01422   while (IsArticulatedPart(v)) v = v->Previous();
    01423   Vehicle *first = v->First();
    01424
    01425   /* make sure the vehicle is stopped in the depot */
    01426   if (CheckTrainStoppedInDepot(first) < 0) {
    01427     return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
    01428   }
    01429
    01430   if (IsRearDualheaded(v)) return_cmd_error(STR_REAR_ENGINE_FOLLOW_FRONT_ERROR);
    01431
    01432   if (flags & DC_EXEC) {
    01433     if (v == first && IsFrontEngine(first)) {
    01434       w = FindWindowById(WC_VEHICLE_VIEW, first->index);
    01435       if (w != NULL) DeleteWindow(w);
    01436     }
    01437     InvalidateWindow(WC_VEHICLE_DEPOT, first->tile);
    01438     RebuildVehicleLists();
    01439   }
    01440
    01441   CommandCost cost(EXPENSES_NEW_VEHICLES);
    01442   switch (p2) {
    01443     case 0: case 2: { /* Delete given wagon */
    01444       bool switch_engine = false;    // update second wagon to engine?
    01445       byte ori_subtype = v->subtype; // backup subtype of deleted wagon in case DeleteVehicle() changes
    01446
    01447       /* 1. Delete the engine, if it is dualheaded also delete the matching
    01448        * rear engine of the loco (from the point of deletion onwards) */
    01449       Vehicle *rear = (IsMultiheaded(v) &&
    01450         IsTrainEngine(v)) ? v->u.rail.other_multiheaded_part : NULL;
    01451
    01452       if (rear != NULL) {
    01453         cost.AddCost(-rear->value);
    01454         if (flags & DC_EXEC) {
    01455           UnlinkWagon(rear, first);
    01456           DeleteDepotHighlightOfVehicle(rear);
    01457           delete rear;
    01458         }
    01459       }
    01460
    01461       /* 2. We are selling the first engine, some special action might be required
    01462        * here, so take attention */
    01463       if ((flags & DC_EXEC) && v == first) {
    01464         Vehicle *new_f = GetNextVehicle(first);
    01465
    01466         /* 2.2 If there are wagons present after the deleted front engine, check
    01467          * if the second wagon (which will be first) is an engine. If it is one,
    01468          * promote it as a new train, retaining the unitnumber, orders */
    01469         if (new_f != NULL && IsTrainEngine(new_f)) {
    01470           switch_engine = true;
    01471           /* Copy important data from the front engine */
    01472           new_f->unitnumber      = first->unitnumber;
    01473           new_f->current_order   = first->current_order;
    01474           new_f->cur_order_index = first->cur_order_index;
    01475           new_f->orders          = first->orders;
    01476           new_f->num_orders      = first->num_orders;
    01477           new_f->group_id        = first->group_id;
    01478
    01479           if (first->prev_shared != NULL) {
    01480             first->prev_shared->next_shared = new_f;
    01481             new_f->prev_shared = first->prev_shared;
    01482           }
    01483
    01484           if (first->next_shared != NULL) {
    01485             first->next_shared->prev_shared = new_f;
    01486             new_f->next_shared = first->next_shared;
    01487           }
    01488
    01489           /*
    01490            * Remove all order information from the front train, to
    01491            * prevent the order and the shared order list to be
    01492            * destroyed by Destroy/DeleteVehicle.
    01493            */
    01494           first->orders      = NULL;
    01495           first->prev_shared = NULL;
    01496           first->next_shared = NULL;
    01497           first->group_id    = DEFAULT_GROUP;
    01498
    01499           /* If we deleted a window then open a new one for the 'new' train */
    01500           if (IsLocalPlayer() && w != NULL) ShowVehicleViewWindow(new_f);
    01501         }
    01502       }
    01503
    01504       /* 3. Delete the requested wagon */
    01505       cost.AddCost(-v->value);
    01506       if (flags & DC_EXEC) {
    01507         first = UnlinkWagon(v, first);
    01508         DeleteDepotHighlightOfVehicle(v);
    01509         delete v;
    01510
    01511         /* 4 If the second wagon was an engine, update it to front_engine
    01512           * which UnlinkWagon() has changed to TS_Free_Car */
    01513         if (switch_engine) SetFrontEngine(first);
    01514
    01515         /* 5. If the train still exists, update its acceleration, window, etc. */
    01516         if (first != NULL) {
    01517           NormaliseTrainConsist(first);
    01518           TrainConsistChanged(first, false);
    01519           UpdateTrainGroupID(first);
    01520           if (IsFrontEngine(first)) InvalidateWindow(WC_VEHICLE_REFIT, first->index);
    01521         }
    01522
    01523
    01524         /* (6.) Borked AI. If it sells an engine it expects all wagons lined
    01525          * up on a new line to be added to the newly built loco. Replace it is.
    01526          * Totally braindead cause building a new engine adds all loco-less
    01527          * engines to its train anyways */
    01528         if (p2 == 2 && HasBit(ori_subtype, TS_FRONT)) {
    01529           Vehicle *tmp;
    01530           for (v = first; v != NULL; v = tmp) {
    01531             tmp = GetNextVehicle(v);
    01532             DoCommand(v->tile, v->index | INVALID_VEHICLE << 16, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
    01533           }
    01534         }
    01535       }
    01536     } break;
    01537     case 1: { /* Delete wagon and all wagons after it given certain criteria */
    01538       /* Start deleting every vehicle after the selected one
    01539        * If we encounter a matching rear-engine to a front-engine
    01540        * earlier in the chain (before deletion), leave it alone */
    01541       Vehicle *tmp;
    01542       for (; v != NULL; v = tmp) {
    01543         tmp = GetNextVehicle(v);
    01544
    01545         if (IsMultiheaded(v)) {
    01546           if (IsTrainEngine(v)) {
    01547             /* We got a front engine of a multiheaded set. Now we will sell the rear end too */
    01548             Vehicle *rear = v->u.rail.other_multiheaded_part;
    01549
    01550             if (rear != NULL) {
    01551               cost.AddCost(-rear->value);
    01552
    01553               /* If this is a multiheaded vehicle with nothing
    01554                * between the parts, tmp will be pointing to the
    01555                * rear part, which is unlinked from the train and
    01556                * deleted here. However, because tmp has already
    01557                * been set it needs to be updated now so that the
    01558                * loop never sees the rear part. */
    01559               if (tmp == rear) tmp = GetNextVehicle(tmp);
    01560
    01561               if (flags & DC_EXEC) {
    01562                 first = UnlinkWagon(rear, first);
    01563                 DeleteDepotHighlightOfVehicle(rear);
    01564                 delete rear;
    01565               }
    01566             }
    01567           } else if (v->u.rail.other_multiheaded_part != NULL) {
    01568             /* The front to this engine is earlier in this train. Do nothing */
    01569             continue;
    01570           }
    01571         }
    01572
    01573         cost.AddCost(-v->value);
    01574         if (flags & DC_EXEC) {
    01575           first = UnlinkWagon(v, first);
    01576           DeleteDepotHighlightOfVehicle(v);
    01577           delete v;
    01578         }
    01579       }
    01580
    01581       /* 3. If it is still a valid train after selling, update its acceleration and cached values */
    01582       if (flags & DC_EXEC && first != NULL) {
    01583         NormaliseTrainConsist(first);
    01584         TrainConsistChanged(first, false);
    01585         UpdateTrainGroupID(first);
    01586         InvalidateWindow(WC_VEHICLE_REFIT, first->index);
    01587       }
    01588     } break;
    01589   }
    01590   return cost;
    01591 }
    01592
    01593 void Train::UpdateDeltaXY(Direction direction)
    01594 {
    01595 #define MKIT(a, b, c, d) ((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | ((d & 0xFF) << 0)
    01596   static const uint32 _delta_xy_table[8] = {
    01597     MKIT(3, 3, -1, -1),
    01598     MKIT(3, 7, -1, -3),
    01599     MKIT(3, 3, -1, -1),
    01600     MKIT(7, 3, -3, -1),
    01601     MKIT(3, 3, -1, -1),
    01602     MKIT(3, 7, -1, -3),
    01603     MKIT(3, 3, -1, -1),
    01604     MKIT(7, 3, -3, -1),
    01605   };
    01606 #undef MKIT
    01607
    01608   uint32 x = _delta_xy_table[direction];
    01609   this->x_offs        = GB(x,  0, 8);
    01610   this->y_offs        = GB(x,  8, 8);
    01611   this->sprite_width  = GB(x, 16, 8);
    01612   this->sprite_height = GB(x, 24, 8);
    01613   this->z_height      = 6;
    01614 }
    01615
    01616 static void UpdateVarsAfterSwap(Vehicle *v)
    01617 {
    01618   v->UpdateDeltaXY(v->direction);
    01619   v->cur_image = v->GetImage(v->direction);
    01620   BeginVehicleMove(v);
    01621   VehiclePositionChanged(v);
    01622   EndVehicleMove(v);
    01623 }
    01624
    01625 static inline void SetLastSpeed(Vehicle* v, int spd)
    01626 {
    01627   int old = v->u.rail.last_speed;
    01628   if (spd != old) {
    01629     v->u.rail.last_speed = spd;
    01630     if (_patches.vehicle_speed || (old == 0) != (spd == 0))
    01631       InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
    01632   }
    01633 }
    01634
    01635 static void SwapTrainFlags(byte *swap_flag1, byte *swap_flag2)
    01636 {
    01637   byte flag1 = *swap_flag1;
    01638   byte flag2 = *swap_flag2;
    01639
    01640   /* Clear the flags */
    01641   ClrBit(*swap_flag1, VRF_GOINGUP);
    01642   ClrBit(*swap_flag1, VRF_GOINGDOWN);
    01643   ClrBit(*swap_flag2, VRF_GOINGUP);
    01644   ClrBit(*swap_flag2, VRF_GOINGDOWN);
    01645
    01646   /* Reverse the rail-flags (if needed) */
    01647   if (HasBit(flag1, VRF_GOINGUP)) {
    01648     SetBit(*swap_flag2, VRF_GOINGDOWN);
    01649   } else if (HasBit(flag1, VRF_GOINGDOWN)) {
    01650     SetBit(*swap_flag2, VRF_GOINGUP);
    01651   }
    01652   if (HasBit(flag2, VRF_GOINGUP)) {
    01653     SetBit(*swap_flag1, VRF_GOINGDOWN);
    01654   } else if (HasBit(flag2, VRF_GOINGDOWN)) {
    01655     SetBit(*swap_flag1, VRF_GOINGUP);
    01656   }
    01657 }
    01658
    01659 static void ReverseTrainSwapVeh(Vehicle *v, int l, int r)
    01660 {
    01661   Vehicle *a, *b;
    01662
    01663   /* locate vehicles to swap */
    01664   for (a = v; l != 0; l--) a = a->Next();
    01665   for (b = v; r != 0; r--) b = b->Next();
    01666
    01667   if (a != b) {
    01668     /* swap the hidden bits */
    01669     {
    01670       uint16 tmp = (a->vehstatus & ~VS_HIDDEN) | (b->vehstatus&VS_HIDDEN);
    01671       b->vehstatus = (b->vehstatus & ~VS_HIDDEN) | (a->vehstatus&VS_HIDDEN);
    01672       a->vehstatus = tmp;
    01673     }
    01674
    01675     Swap(a->u.rail.track, b->u.rail.track);
    01676     Swap(a->direction,    b->direction);
    01677
    01678     /* toggle direction */
    01679     if (a->u.rail.track != TRACK_BIT_DEPOT) a->direction = ReverseDir(a->direction);
    01680     if (b->u.rail.track != TRACK_BIT_DEPOT) b->direction = ReverseDir(b->direction);
    01681
    01682     Swap(a->x_pos, b->x_pos);
    01683     Swap(a->y_pos, b->y_pos);
    01684     Swap(a->tile,  b->tile);
    01685     Swap(a->z_pos, b->z_pos);
    01686
    01687     SwapTrainFlags(&a->u.rail.flags, &b->u.rail.flags);
    01688
    01689     /* update other vars */
    01690     UpdateVarsAfterSwap(a);
    01691     UpdateVarsAfterSwap(b);
    01692
    01693     /* call the proper EnterTile function unless we are in a wormhole */
    01694     if (a->u.rail.track != TRACK_BIT_WORMHOLE) VehicleEnterTile(a, a->tile, a->x_pos, a->y_pos);
    01695     if (b->u.rail.track != TRACK_BIT_WORMHOLE) VehicleEnterTile(b, b->tile, b->x_pos, b->y_pos);
    01696   } else {
    01697     if (a->u.rail.track != TRACK_BIT_DEPOT) a->direction = ReverseDir(a->direction);
    01698     UpdateVarsAfterSwap(a);
    01699
    01700     if (a->u.rail.track != TRACK_BIT_WORMHOLE) VehicleEnterTile(a, a->tile, a->x_pos, a->y_pos);
    01701   }
    01702
    01703   /* Update train's power incase tiles were different rail type */
    01704   TrainPowerChanged(v);
    01705 }
    01706
    01707
    01713 static void *TrainOnTileEnum(Vehicle *v, void *)
    01714 {
    01715   return (v->type == VEH_TRAIN) ? v : NULL;
    01716 }
    01717
    01718
    01725 static void *TrainApproachingCrossingEnum(Vehicle *v, void *data)
    01726 {
    01727   /* not a train || not front engine || crashed */
    01728   if (v->type != VEH_TRAIN || !IsFrontEngine(v) || v->vehstatus & VS_CRASHED) return NULL;
    01729
    01730   TileIndex tile = *(TileIndex*)data;
    01731
    01732   if (TrainApproachingCrossingTile(v) != tile) return NULL;
    01733
    01734   return v;
    01735 }
    01736
    01737
    01744 static bool TrainApproachingCrossing(TileIndex tile)
    01745 {
    01746   assert(IsLevelCrossingTile(tile));
    01747
    01748   DiagDirection dir = AxisToDiagDir(GetCrossingRailAxis(tile));
    01749   TileIndex tile_from = tile + TileOffsByDiagDir(dir);
    01750
    01751   if (HasVehicleOnPos(tile_from, &tile, &TrainApproachingCrossingEnum)) return true;
    01752
    01753   dir = ReverseDiagDir(dir);
    01754   tile_from = tile + TileOffsByDiagDir(dir);
    01755
    01756   return HasVehicleOnPos(tile_from, &tile, &TrainApproachingCrossingEnum);
    01757 }
    01758
    01759
    01766 void UpdateLevelCrossing(TileIndex tile, bool sound)
    01767 {
    01768   assert(IsLevelCrossingTile(tile));
    01769
    01770   /* train on crossing || train approaching crossing || reserved */
    01771   bool new_state = HasVehicleOnPos(tile, NULL, &TrainOnTileEnum) || TrainApproachingCrossing(tile);
    01772
    01773   if (new_state != IsCrossingBarred(tile)) {
    01774     if (new_state && sound) {
    01775       SndPlayTileFx(SND_0E_LEVEL_CROSSING, tile);
    01776     }
    01777     SetCrossingBarred(tile, new_state);
    01778     MarkTileDirtyByTile(tile);
    01779   }
    01780 }
    01781
    01782
    01788 static inline void MaybeBarCrossingWithSound(TileIndex tile)
    01789 {
    01790   if (!IsCrossingBarred(tile)) {
    01791     BarCrossing(tile);
    01792     SndPlayTileFx(SND_0E_LEVEL_CROSSING, tile);
    01793     MarkTileDirtyByTile(tile);
    01794   }
    01795 }
    01796
    01797
    01803 static void AdvanceWagonsBeforeSwap(Vehicle *v)
    01804 {
    01805   Vehicle *base = v;
    01806   Vehicle *first = base;                    // first vehicle to move
    01807   Vehicle *last = GetLastVehicleInChain(v); // last vehicle to move
    01808   uint length = CountVehiclesInChain(v);
    01809
    01810   while (length > 2) {
    01811     last = last->Previous();
    01812     first = first->Next();
    01813
    01814     int differential = base->u.rail.cached_veh_length - last->u.rail.cached_veh_length;
    01815
    01816     /* do not update images now
    01817      * negative differential will be handled in AdvanceWagonsAfterSwap() */
    01818     for (int i = 0; i < differential; i++) TrainController(first, last->Next(), false);
    01819
    01820     base = first; // == base->Next()
    01821     length -= 2;
    01822   }
    01823 }
    01824
    01825
    01831 static void AdvanceWagonsAfterSwap(Vehicle *v)
    01832 {
    01833   /* first of all, fix the situation when the train was entering a depot */
    01834   Vehicle *dep = v; // last vehicle in front of just left depot
    01835   while (dep->Next() != NULL && (dep->u.rail.track == TRACK_BIT_DEPOT || dep->Next()->u.rail.track != TRACK_BIT_DEPOT)) {
    01836     dep = dep->Next(); // find first vehicle outside of a depot, with next vehicle inside a depot
    01837   }
    01838
    01839   Vehicle *leave = dep->Next(); // first vehicle in a depot we are leaving now
    01840
    01841   if (leave != NULL) {
    01842     /* 'pull' next wagon out of the depot, so we won't miss it (it could stay in depot forever) */
    01843     int d = TicksToLeaveDepot(dep);
    01844
    01845     if (d <= 0) {
    01846       leave->vehstatus &= ~VS_HIDDEN; // move it out of the depot
    01847       leave->u.rail.track = AxisToTrackBits(DiagDirToAxis(GetRailDepotDirection(leave->tile)));
    01848       for (int i = 0; i >= d; i--) TrainController(leave, NULL, false); // maybe move it, and maybe let another wagon leave
    01849     }
    01850   } else {
    01851     dep = NULL; // no vehicle in a depot, so no vehicle leaving a depot
    01852   }
    01853
    01854   Vehicle *base = v;
    01855   Vehicle *first = base;                    // first vehicle to move
    01856   Vehicle *last = GetLastVehicleInChain(v); // last vehicle to move
    01857   uint length = CountVehiclesInChain(v);
    01858
    01859   /* we have to make sure all wagons that leave a depot because of train reversing are moved coorectly
    01860    * they have already correct spacing, so we have to make sure they are moved how they should */
    01861   bool nomove = (dep == NULL); // if there is no vehicle leaving a depot, limit the number of wagons moved immediatelly
    01862
    01863   while (length > 2) {
    01864     /* we reached vehicle (originally) in front of a depot, stop now
    01865      * (we would move wagons that are alredy moved with new wagon length) */
    01866     if (base == dep) break;
    01867
    01868     /* the last wagon was that one leaving a depot, so do not move it anymore */
    01869     if (last == dep) nomove = true;
    01870
    01871     last = last->Previous();
    01872     first = first->Next();
    01873
    01874     int differential = last->u.rail.cached_veh_length - base->u.rail.cached_veh_length;
    01875
    01876     /* do not update images now */
    01877     for (int i = 0; i < differential; i++) TrainController(first, (nomove ? last->Next() : NULL), false);
    01878
    01879     base = first; // == base->Next()
    01880     length -= 2;
    01881   }
    01882 }
    01883
    01884
    01885 static void ReverseTrainDirection(Vehicle *v)
    01886 {
    01887   if (IsTileDepotType(v->tile, TRANSPORT_RAIL)) {
    01888     InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
    01889   }
    01890
    01891   /* Check if we were approaching a rail/road-crossing */
    01892   TileIndex crossing = TrainApproachingCrossingTile(v);
    01893
    01894   /* count number of vehicles */
    01895   int r = 0;
    01896   for (const Vehicle *u = v; (u = u->Next()) != NULL;) { r++; }
    01897
    01898   AdvanceWagonsBeforeSwap(v);
    01899
    01900   /* swap start<>end, start+1<>end-1, ... */
    01901   int l = 0;
    01902   do {
    01903     ReverseTrainSwapVeh(v, l++, r--);
    01904   } while (l <= r);
    01905
    01906   AdvanceWagonsAfterSwap(v);
    01907
    01908   if (IsTileDepotType(v->tile, TRANSPORT_RAIL)) {
    01909     InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
    01910   }
    01911
    01912   /* set reversed flag on all parts */
    01913   for (Vehicle *u = v; u != NULL; u = u->Next()) ToggleBit(u->u.rail.flags, VRF_TOGGLE_REVERSE);
    01914
    01915   ClrBit(v->u.rail.flags, VRF_REVERSING);
    01916
    01917   /* recalculate cached data */
    01918   TrainConsistChanged(v, true);
    01919
    01920   /* update all images */
    01921   for (Vehicle *u = v; u != NULL; u = u->Next()) u->cur_image = u->GetImage(u->direction);
    01922
    01923   /* update crossing we were approaching */
    01924   if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing);
    01925
    01926   /* maybe we are approaching crossing now, after reversal */
    01927   crossing = TrainApproachingCrossingTile(v);
    01928   if (crossing != INVALID_TILE) MaybeBarCrossingWithSound(crossing);
    01929 }
    01930
    01937 CommandCost CmdReverseTrainDirection(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    01938 {
    01939   if (!IsValidVehicleID(p1)) return CMD_ERROR;
    01940
    01941   Vehicle *v = GetVehicle(p1);
    01942
    01943   if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR;
    01944
    01945   if (p2) {
    01946     /* turn a single unit around */
    01947
    01948     if (IsMultiheaded(v) || HasBit(EngInfo(v->engine_type)->callbackmask, CBM_VEHICLE_ARTIC_ENGINE)) {
    01949       return_cmd_error(STR_ONLY_TURN_SINGLE_UNIT);
    01950     }
    01951
    01952     Vehicle *front = v->First();
    01953     /* make sure the vehicle is stopped in the depot */
    01954     if (CheckTrainStoppedInDepot(front) < 0) {
    01955       return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
    01956     }
    01957
    01958     if (flags & DC_EXEC) {
    01959       ToggleBit(v->u.rail.flags, VRF_REVERSE_DIRECTION);
    01960       InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
    01961       InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
    01962     }
    01963   } else {
    01964     /* turn the whole train around */
    01965     if (v->vehstatus & VS_CRASHED || v->breakdown_ctr != 0) return CMD_ERROR;
    01966
    01967     if (flags & DC_EXEC) {
    01968       if (_patches.realistic_acceleration && v->cur_speed != 0) {
    01969         ToggleBit(v->u.rail.flags, VRF_REVERSING);
    01970       } else {
    01971         v->cur_speed = 0;
    01972         SetLastSpeed(v, 0);
    01973         HideFillingPercent(&v->fill_percent_te_id);
    01974         ReverseTrainDirection(v);
    01975       }
    01976     }
    01977   }
    01978   return CommandCost();
    01979 }
    01980
    01987 CommandCost CmdForceTrainProceed(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    01988 {
    01989   if (!IsValidVehicleID(p1)) return CMD_ERROR;
    01990
    01991   Vehicle *v = GetVehicle(p1);
    01992
    01993   if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR;
    01994
    01995   if (flags & DC_EXEC) v->u.rail.force_proceed = 0x50;
    01996
    01997   return CommandCost();
    01998 }
    01999
    02010 CommandCost CmdRefitRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    02011 {
    02012   CargoID new_cid = GB(p2, 0, 8);
    02013   byte new_subtype = GB(p2, 8, 8);
    02014   bool only_this = HasBit(p2, 16);
    02015
    02016   if (!IsValidVehicleID(p1)) return CMD_ERROR;
    02017
    02018   Vehicle *v = GetVehicle(p1);
    02019
    02020   if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR;
    02021   if (CheckTrainStoppedInDepot(v) < 0) return_cmd_error(STR_TRAIN_MUST_BE_STOPPED);
    02022   if (v->vehstatus & VS_CRASHED) return_cmd_error(STR_CAN_T_REFIT_DESTROYED_VEHICLE);
    02023
    02024   /* Check cargo */
    02025   if (new_cid >= NUM_CARGO) return CMD_ERROR;
    02026
    02027   CommandCost cost(EXPENSES_TRAIN_RUN);
    02028   uint num = 0;
    02029
    02030   do {
    02031     /* XXX: We also refit all the attached wagons en-masse if they
    02032      * can be refitted. This is how TTDPatch does it.  TODO: Have
    02033      * some nice [Refit] button near each wagon. --pasky */
    02034     if (!CanRefitTo(v->engine_type, new_cid)) continue;
    02035
    02036     if (v->cargo_cap != 0) {
    02037       uint16 amount = CALLBACK_FAILED;
    02038
    02039       if (HasBit(EngInfo(v->engine_type)->callbackmask, CBM_VEHICLE_REFIT_CAPACITY)) {
    02040         /* Back up the vehicle's cargo type */
    02041         CargoID temp_cid = v->cargo_type;
    02042         byte temp_subtype = v->cargo_subtype;
    02043         v->cargo_type = new_cid;
    02044         v->cargo_subtype = new_subtype;
    02045         /* Check the refit capacity callback */
    02046         amount = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, v->engine_type, v);
    02047         /* Restore the original cargo type */
    02048         v->cargo_type = temp_cid;
    02049         v->cargo_subtype = temp_subtype;
    02050       }
    02051
    02052       if (amount == CALLBACK_FAILED) { // callback failed or not used, use default
    02053         const RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
    02054         CargoID old_cid = rvi->cargo_type;
    02055         /* normally, the capacity depends on the cargo type, a rail vehicle can
    02056          * carry twice as much mail/goods as normal cargo, and four times as
    02057          * many passengers
    02058          */
    02059         amount = rvi->capacity;
    02060         switch (old_cid) {
    02061           case CT_PASSENGERS: break;
    02062           case CT_MAIL:
    02063           case CT_GOODS: amount *= 2; break;
    02064           default:       amount *= 4; break;
    02065         }
    02066         switch (new_cid) {
    02067           case CT_PASSENGERS: break;
    02068           case CT_MAIL:
    02069           case CT_GOODS: amount /= 2; break;
    02070           default:       amount /= 4; break;
    02071         }
    02072       }
    02073
    02074       if (amount != 0) {
    02075         if (new_cid != v->cargo_type) {
    02076           cost.AddCost(GetRefitCost(v->engine_type));
    02077         }
    02078
    02079         num += amount;
    02080         if (flags & DC_EXEC) {
    02081           v->cargo.Truncate((v->cargo_type == new_cid) ? amount : 0);
    02082           v->cargo_type = new_cid;
    02083           v->cargo_cap = amount;
    02084           v->cargo_subtype = new_subtype;
    02085           InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
    02086           InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
    02087           RebuildVehicleLists();
    02088         }
    02089       }
    02090     }
    02091   } while ((v = v->Next()) != NULL && !only_this);
    02092
    02093   _returned_refit_capacity = num;
    02094
    02095   /* Update the train's cached variables */
    02096   if (flags & DC_EXEC) TrainConsistChanged(GetVehicle(p1)->First(), false);
    02097
    02098   return cost;
    02099 }
    02100
    02101 struct TrainFindDepotData {
    02102   uint best_length;
    02103   TileIndex tile;
    02104   PlayerID owner;
    02109   bool reverse;
    02110 };
    02111
    02112 static bool NtpCallbFindDepot(TileIndex tile, TrainFindDepotData *tfdd, int track, uint length)
    02113 {
    02114   if (IsTileType(tile, MP_RAILWAY) &&
    02115       IsTileOwner(tile, tfdd->owner) &&
    02116       IsRailDepot(tile)) {
    02117     /* approximate number of tiles by dividing by DIAG_FACTOR */
    02118     tfdd->best_length = length / DIAG_FACTOR;
    02119     tfdd->tile = tile;
    02120     return true;
    02121   }
    02122
    02123   return false;
    02124 }
    02125
    02128 static TrainFindDepotData FindClosestTrainDepot(Vehicle *v, int max_distance)
    02129 {
    02130   assert(!(v->vehstatus & VS_CRASHED));
    02131
    02132   TrainFindDepotData tfdd;
    02133   tfdd.owner = v->owner;
    02134   tfdd.best_length = UINT_MAX;
    02135   tfdd.reverse = false;
    02136
    02137   TileIndex tile = v->tile;
    02138   if (IsTileDepotType(tile, TRANSPORT_RAIL)) {
    02139     tfdd.tile = tile;
    02140     tfdd.best_length = 0;
    02141     return tfdd;
    02142   }
    02143
    02144   switch (_patches.pathfinder_for_trains) {
    02145     case VPF_YAPF: { /* YAPF */
    02146       bool found = YapfFindNearestRailDepotTwoWay(v, max_distance, NPF_INFINITE_PENALTY, &tfdd.tile, &tfdd.reverse);
    02147       tfdd.best_length = found ? max_distance / 2 : UINT_MAX; // some fake distance or NOT_FOUND
    02148     } break;
    02149
    02150     case VPF_NPF: { /* NPF */
    02151       Vehicle* last = GetLastVehicleInChain(v);
    02152       Trackdir trackdir = GetVehicleTrackdir(v);
    02153       Trackdir trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last));
    02154
    02155       assert(trackdir != INVALID_TRACKDIR);
    02156       NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, TRANSPORT_RAIL, 0, v->owner, v->u.rail.compatible_railtypes, NPF_INFINITE_PENALTY);
    02157       if (ftd.best_bird_dist == 0) {
    02158         /* Found target */
    02159         tfdd.tile = ftd.node.tile;
    02160         /* Our caller expects a number of tiles, so we just approximate that
    02161         * number by this. It might not be completely what we want, but it will
    02162         * work for now :-) We can possibly change this when the old pathfinder
    02163         * is removed. */
    02164         tfdd.best_length = ftd.best_path_dist / NPF_TILE_LENGTH;
    02165         if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)) tfdd.reverse = true;
    02166       }
    02167     } break;
    02168
    02169     default:
    02170     case VPF_NTP: { /* NTP */
    02171       /* search in the forward direction first. */
    02172       DiagDirection i = TrainExitDir(v->direction, v->u.rail.track);
    02173       NewTrainPathfind(tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd);
    02174       if (tfdd.best_length == UINT_MAX){
    02175         tfdd.reverse = true;
    02176         /* search in backwards direction */
    02177         i = TrainExitDir(ReverseDir(v->direction), v->u.rail.track);
    02178         NewTrainPathfind(tile, 0, v->u.rail.compatible_railtypes, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd);
    02179       }
    02180     } break;
    02181   }
    02182
    02183   return tfdd;
    02184 }
    02185
    02194 CommandCost CmdSendTrainToDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    02195 {
    02196   if (p2 & DEPOT_MASS_SEND) {
    02197     /* Mass goto depot requested */
    02198     if (!ValidVLWFlags(p2 & VLW_MASK)) return CMD_ERROR;
    02199     return SendAllVehiclesToDepot(VEH_TRAIN, flags, p2 & DEPOT_SERVICE, _current_player, (p2 & VLW_MASK), p1);
    02200   }
    02201
    02202   if (!IsValidVehicleID(p1)) return CMD_ERROR;
    02203
    02204   Vehicle *v = GetVehicle(p1);
    02205
    02206   if (v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR;
    02207
    02208   if (v->vehstatus & VS_CRASHED) return CMD_ERROR;
    02209
    02210   if (v->current_order.type == OT_GOTO_DEPOT) {
    02211     if (!!(p2 & DEPOT_SERVICE) == HasBit(v->current_order.flags, OF_HALT_IN_DEPOT)) {
    02212       /* We called with a different DEPOT_SERVICE setting.
    02213        * Now we change the setting to apply the new one and let the vehicle head for the same depot.
    02214        * Note: the if is (true for requesting service == true for ordered to stop in depot)          */
    02215       if (flags & DC_EXEC) {
    02216         ClrBit(v->current_order.flags, OF_PART_OF_ORDERS);
    02217         ToggleBit(v->current_order.flags, OF_HALT_IN_DEPOT);
    02218         InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
    02219       }
    02220       return CommandCost();
    02221     }
    02222
    02223     if (p2 & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
    02224     if (flags & DC_EXEC) {
    02225       if (HasBit(v->current_order.flags, OF_PART_OF_ORDERS)) {
    02226         v->cur_order_index++;
    02227       }
    02228
    02229       v->current_order.type = OT_DUMMY;
    02230       v->current_order.flags = 0;
    02231       InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
    02232     }
    02233     return CommandCost();
    02234   }
    02235
    02236   /* check if at a standstill (not stopped only) in a depot
    02237    * the check is down here to make it possible to alter stop/service for trains entering the depot */
    02238   if (IsTileDepotType(v->tile, TRANSPORT_RAIL) && v->cur_speed == 0) return CMD_ERROR;
    02239
    02240   TrainFindDepotData tfdd = FindClosestTrainDepot(v, 0);
    02241   if (tfdd.best_length == (uint)-1) return_cmd_error(STR_883A_UNABLE_TO_FIND_ROUTE_TO);
    02242
    02243   if (flags & DC_EXEC) {
    02244     if (v->current_order.type == OT_LOADING) v->LeaveStation();
    02245
    02246     v->dest_tile = tfdd.tile;
    02247     v->current_order.type = OT_GOTO_DEPOT;
    02248     v->current_order.flags = OFB_NON_STOP;
    02249     if (!(p2 & DEPOT_SERVICE)) SetBit(v->current_order.flags, OF_HALT_IN_DEPOT);
    02250     v->current_order.dest = GetDepotByTile(tfdd.tile)->index;
    02251     v->current_order.refit_cargo = CT_INVALID;
    02252     InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
    02253     /* If there is no depot in front, reverse automatically */
    02254     if (tfdd.reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
    02255   }
    02256
    02257   return CommandCost();
    02258 }
    02259
    02260
    02261 void OnTick_Train()
    02262 {
    02263   _age_cargo_skip_counter = (_age_cargo_skip_counter == 0) ? 184 : (_age_cargo_skip_counter - 1);
    02264 }
    02265
    02266 static const int8 _vehicle_smoke_pos[8] = {
    02267   1, 1, 1, 0, -1, -1, -1, 0
    02268 };
    02269
    02270 static void HandleLocomotiveSmokeCloud(const Vehicle* v)
    02271 {
    02272   bool sound = false;
    02273
    02274   if (v->vehstatus & VS_TRAIN_SLOWING || v->load_unload_time_rem != 0 || v->cur_speed < 2)
    02275     return;
    02276
    02277   const Vehicle* u = v;
    02278
    02279   do {
    02280     const RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
    02281     int effect_offset = GB(v->u.rail.cached_vis_effect, 0, 4) - 8;
    02282     byte effect_type = GB(v->u.rail.cached_vis_effect, 4, 2);
    02283     bool disable_effect = HasBit(v->u.rail.cached_vis_effect, 6);
    02284
    02285     /* no smoke? */
    02286     if ((rvi->railveh_type == RAILVEH_WAGON && effect_type == 0) ||
    02287         disable_effect ||
    02288         v->vehstatus & VS_HIDDEN) {
    02289       continue;
    02290     }
    02291
    02292     /* No smoke in depots or tunnels */
    02293     if (IsTileDepotType(v->tile, TRANSPORT_RAIL) || IsTunnelTile(v->tile)) continue;
    02294
    02295     /* No sparks for electric vehicles on nonelectrified tracks */
    02296     if (!HasPowerOnRail(v->u.rail.railtype, GetTileRailType(v->tile))) continue;
    02297
    02298     if (effect_type == 0) {
    02299       /* Use default effect type for engine class. */
    02300       effect_type = rvi->engclass;
    02301     } else {
    02302       effect_type--;
    02303     }
    02304
    02305     int x = _vehicle_smoke_pos[v->direction] * effect_offset;
    02306     int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
    02307
    02308     if (HasBit(v->u.rail.flags, VRF_REVERSE_DIRECTION)) {
    02309       x = -x;
    02310       y = -y;
    02311     }
    02312
    02313     switch (effect_type) {
    02314     case 0:
    02315       /* steam smoke. */
    02316       if (GB(v->tick_counter, 0, 4) == 0) {
    02317         CreateEffectVehicleRel(v, x, y, 10, EV_STEAM_SMOKE);
    02318         sound = true;
    02319       }
    02320       break;
    02321
    02322     case 1:
    02323       /* diesel smoke */
    02324       if (u->cur_speed <= 40 && Chance16(15, 128)) {
    02325         CreateEffectVehicleRel(v, 0, 0, 10, EV_DIESEL_SMOKE);
    02326         sound = true;
    02327       }
    02328       break;
    02329
    02330     case 2:
    02331       /* blue spark */
    02332       if (GB(v->tick_counter, 0, 2) == 0 && Chance16(1, 45)) {
    02333         CreateEffectVehicleRel(v, 0, 0, 10, EV_ELECTRIC_SPARK);
    02334         sound = true;
    02335       }
    02336       break;
    02337     }
    02338   } while ((v = v->Next()) != NULL);
    02339
    02340   if (sound) PlayVehicleSound(u, VSE_TRAIN_EFFECT);
    02341 }
    02342
    02343 void Train::PlayLeaveStationSound() const
    02344 {
    02345   static const SoundFx sfx[] = {
    02346     SND_04_TRAIN,
    02347     SND_0A_TRAIN_HORN,
    02348     SND_0A_TRAIN_HORN,
    02349     SND_47_MAGLEV_2,
    02350     SND_41_MAGLEV
    02351   };
    02352
    02353   if (PlayVehicleSound(this, VSE_START)) return;
    02354
    02355   EngineID engtype = this->engine_type;
    02356   SndPlayVehicleFx(sfx[RailVehInfo(engtype)->engclass], this);
    02357 }
    02358
    02359 static bool CheckTrainStayInDepot(Vehicle *v)
    02360 {
    02361   /* bail out if not all wagons are in the same depot or not in a depot at all */
    02362   for (const Vehicle *u = v; u != NULL; u = u->Next()) {
    02363     if (u->u.rail.track != TRACK_BIT_DEPOT || u->tile != v->tile) return false;
    02364   }
    02365
    02366   /* if the train got no power, then keep it in the depot */
    02367   if (v->u.rail.cached_power == 0) {
    02368     v->vehstatus |= VS_STOPPED;
    02369     InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
    02370     return true;
    02371   }
    02372
    02373   if (v->u.rail.force_proceed == 0) {
    02374     if (++v->load_unload_time_rem < 37) {
    02375       InvalidateWindowClasses(WC_TRAINS_LIST);
    02376       return true;
    02377     }
    02378
    02379     v->load_unload_time_rem = 0;
    02380
    02381     if (UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner)) {
    02382       InvalidateWindowClasses(WC_TRAINS_LIST);
    02383       return true;
    02384     }
    02385   }
    02386
    02387   VehicleServiceInDepot(v);
    02388   InvalidateWindowClasses(WC_TRAINS_LIST);
    02389   v->PlayLeaveStationSound();
    02390
    02391   v->u.rail.track = TRACK_BIT_X;
    02392   if (v->direction & 2) v->u.rail.track = TRACK_BIT_Y;
    02393
    02394   v->vehstatus &= ~VS_HIDDEN;
    02395   v->cur_speed = 0;
    02396
    02397   v->UpdateDeltaXY(v->direction);
    02398   v->cur_image = v->GetImage(v->direction);
    02399   VehiclePositionChanged(v);
    02400   UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner);
    02401   UpdateTrainAcceleration(v);
    02402   InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
    02403
    02404   return false;
    02405 }
    02406
    02407 /* Check for station tiles */
    02408 struct TrainTrackFollowerData {
    02409   TileIndex dest_coords;
    02410   StationID station_index; // station index we're heading for
    02411   uint best_bird_dist;
    02412   uint best_track_dist;
    02413   TrackdirByte best_track;
    02414 };
    02415
    02416 static bool NtpCallbFindStation(TileIndex tile, TrainTrackFollowerData *ttfd, Trackdir track, uint length)
    02417 {
    02418   /* heading for nowhere? */
    02419   if (ttfd->dest_coords == 0) return false;
    02420
    02421   /* did we reach the final station? */
    02422   if ((ttfd->station_index == INVALID_STATION && tile == ttfd->dest_coords) || (
    02423         IsTileType(tile, MP_STATION) &&
    02424         IsRailwayStation(tile) &&
    02425         GetStationIndex(tile) == ttfd->station_index
    02426       )) {
    02427     /* We do not check for dest_coords if we have a station_index,
    02428      * because in that case the dest_coords are just an
    02429      * approximation of where the station is */
    02430
    02431     /* found station */
    02432     ttfd->best_track = track;
    02433     ttfd->best_bird_dist = 0;
    02434     return true;
    02435   } else {
    02436     /* didn't find station, keep track of the best path so far. */
    02437     uint dist = DistanceManhattan(tile, ttfd->dest_coords);
    02438     if (dist < ttfd->best_bird_dist) {
    02439       ttfd->best_bird_dist = dist;
    02440       ttfd->best_track = track;
    02441     }
    02442     return false;
    02443   }
    02444 }
    02445
    02446 static void FillWithStationData(TrainTrackFollowerData* fd, const Vehicle* v)
    02447 {
    02448   fd->dest_coords = v->dest_tile;
    02449   if (v->current_order.type == OT_GOTO_STATION) {
    02450     fd->station_index = v->current_order.dest;
    02451   } else {
    02452     fd->station_index = INVALID_STATION;
    02453   }
    02454 }
    02455
    02456 static const byte _initial_tile_subcoord[6][4][3] = {
    02457 {{ 15, 8, 1 }, { 0, 0, 0 }, { 0, 8, 5 }, { 0,  0, 0 }},
    02458 {{  0, 0, 0 }, { 8, 0, 3 }, { 0, 0, 0 }, { 8, 15, 7 }},
    02459 {{  0, 0, 0 }, { 7, 0, 2 }, { 0, 7, 6 }, { 0,  0, 0 }},
    02460 {{ 15, 8, 2 }, { 0, 0, 0 }, { 0, 0, 0 }, { 8, 15, 6 }},
    02461 {{ 15, 7, 0 }, { 8, 0, 4 }, { 0, 0, 0 }, { 0,  0, 0 }},
    02462 {{  0, 0, 0 }, { 0, 0, 0 }, { 0, 8, 4 }, { 7, 15, 0 }},
    02463 };
    02464
    02465 static const uint32 _reachable_tracks[4] = {
    02466   0x10091009,
    02467   0x00160016,
    02468   0x05200520,
    02469   0x2A002A00,
    02470 };
    02471
    02472 static const byte _search_directions[6][4] = {
    02473   { 0, 9, 2, 9 },
    02474   { 9, 1, 9, 3 },
    02475   { 9, 0, 3, 9 },
    02476   { 1, 9, 9, 2 },
    02477   { 3, 2, 9, 9 },
    02478   { 9, 9, 1, 0 },
    02479 };
    02480
    02481 static const byte _pick_track_table[6] = {1, 3, 2, 2, 0, 0};
    02482
    02483 /* choose a track */
    02484 static Track ChooseTrainTrack(Vehicle* v, TileIndex tile, DiagDirection enterdir, TrackBits tracks)
    02485 {
    02486   Track best_track;
    02487   /* pathfinders are able to tell that route was only 'guessed' */
    02488   bool path_not_found = false;
    02489
    02490 #ifdef PF_BENCHMARK
    02491   TIC()
    02492 #endif
    02493
    02494   assert((tracks & ~TRACK_BIT_MASK) == 0);
    02495
    02496   /* quick return in case only one possible track is available */
    02497   if (KillFirstBit(tracks) == TRACK_BIT_NONE) return FindFirstTrack(tracks);
    02498
    02499   switch (_patches.pathfinder_for_trains) {
    02500     case VPF_YAPF: { /* YAPF */
    02501       Trackdir trackdir = YapfChooseRailTrack(v, tile, enterdir, tracks, &path_not_found);
    02502       if (trackdir != INVALID_TRACKDIR) {
    02503         best_track = TrackdirToTrack(trackdir);
    02504       } else {
    02505         best_track = FindFirstTrack(tracks);
    02506       }
    02507     } break;
    02508
    02509     case VPF_NPF: { /* NPF */
    02510       void *perf = NpfBeginInterval();
    02511
    02512       NPFFindStationOrTileData fstd;
    02513       NPFFillWithOrderData(&fstd, v);
    02514       /* The enterdir for the new tile, is the exitdir for the old tile */
    02515       Trackdir trackdir = GetVehicleTrackdir(v);
    02516       assert(trackdir != INVALID_TRACKDIR);
    02517
    02518       NPFFoundTargetData ftd = NPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, true, &fstd, TRANSPORT_RAIL, 0, v->owner, v->u.rail.compatible_railtypes);
    02519
    02520       if (ftd.best_trackdir == INVALID_TRACKDIR) {
    02521         /* We are already at our target. Just do something
    02522          * @todo maybe display error?
    02523          * @todo: go straight ahead if possible? */
    02524         best_track = FindFirstTrack(tracks);
    02525       } else {
    02526         /* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains
    02527          * the direction we need to take to get there, if ftd.best_bird_dist is not 0,
    02528          * we did not find our target, but ftd.best_trackdir contains the direction leading
    02529          * to the tile closest to our target. */
    02530         if (ftd.best_bird_dist != 0) path_not_found = true;
    02531         /* Discard enterdir information, making it a normal track */
    02532         best_track = TrackdirToTrack(ftd.best_trackdir);
    02533       }
    02534
    02535       int time = NpfEndInterval(perf);
    02536       DEBUG(yapf, 4, "[NPFT] %d us - %d rounds - %d open - %d closed -- ", time, 0, _aystar_stats_open_size, _aystar_stats_closed_size);
    02537     } break;
    02538
    02539     default:
    02540     case VPF_NTP: { /* NTP */
    02541       void *perf = NpfBeginInterval();
    02542
    02543       TrainTrackFollowerData fd;
    02544       FillWithStationData(&fd, v);
    02545
    02546       /* New train pathfinding */
    02547       fd.best_bird_dist = UINT_MAX;
    02548       fd.best_track_dist = UINT_MAX;
    02549       fd.best_track = INVALID_TRACKDIR;
    02550
    02551       NewTrainPathfind(tile - TileOffsByDiagDir(enterdir), v->dest_tile,
    02552         v->u.rail.compatible_railtypes, enterdir, (NTPEnumProc*)NtpCallbFindStation, &fd);
    02553
    02554       /* check whether the path was found or only 'guessed' */
    02555       if (fd.best_bird_dist != 0) path_not_found = true;
    02556
    02557       if (fd.best_track == INVALID_TRACKDIR) {
    02558         /* blaha */
    02559         best_track = FindFirstTrack(tracks);
    02560       } else {
    02561         best_track = TrackdirToTrack(fd.best_track);
    02562       }
    02563
    02564       int time = NpfEndInterval(perf);
    02565       DEBUG(yapf, 4, "[NTPT] %d us - %d rounds - %d open - %d closed -- ", time, 0, 0, 0);
    02566     } break;
    02567   }
    02568
    02569   /* handle "path not found" state */
    02570   if (path_not_found) {
    02571     /* PF didn't find the route */
    02572     if (!HasBit(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION)) {
    02573       /* it is first time the problem occurred, set the "path not found" flag */
    02574       SetBit(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION);
    02575       /* and notify user about the event */
    02576       if (_patches.lost_train_warn && v->owner == _local_player) {
    02577         SetDParam(0, v->unitnumber);
    02578         AddNewsItem(
    02579           STR_TRAIN_IS_LOST,
    02580           NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0),
    02581           v->index,
    02582           0);
    02583       }
    02584     }
    02585   } else {
    02586     /* route found, is the train marked with "path not found" flag? */
    02587     if (HasBit(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION)) {
    02588       /* clear the flag as the PF's problem was solved */
    02589       ClrBit(v->u.rail.flags, VRF_NO_PATH_TO_DESTINATION);
    02590       /* can we also delete the "News" item somehow? */
    02591     }
    02592   }
    02593
    02594 #ifdef PF_BENCHMARK
    02595   TOC("PF time = ", 1)
    02596 #endif
    02597
    02598   return best_track;
    02599 }
    02600
    02601
    02602 static bool CheckReverseTrain(Vehicle *v)
    02603 {
    02604   if (_opt.diff.line_reverse_mode != 0 ||
    02605       v->u.rail.track == TRACK_BIT_DEPOT || v->u.rail.track == TRACK_BIT_WORMHOLE ||
    02606       !(v->direction & 1))
    02607     return false;
    02608
    02609   TrainTrackFollowerData fd;
    02610   FillWithStationData(&fd, v);
    02611
    02612   uint reverse_best = 0;
    02613
    02614   assert(v->u.rail.track);
    02615
    02616   int i = _search_directions[FIND_FIRST_BIT(v->u.rail.track)][DirToDiagDir(v->direction)];
    02617
    02618   switch (_patches.pathfinder_for_trains) {
    02619     case VPF_YAPF: { /* YAPF */
    02620       reverse_best = YapfCheckReverseTrain(v);
    02621     } break;
    02622
    02623     case VPF_NPF: { /* NPF */
    02624       NPFFindStationOrTileData fstd;
    02625       NPFFoundTargetData ftd;
    02626       Vehicle* last = GetLastVehicleInChain(v);
    02627
    02628       NPFFillWithOrderData(&fstd, v);
    02629
    02630       Trackdir trackdir = GetVehicleTrackdir(v);
    02631       Trackdir trackdir_rev = ReverseTrackdir(GetVehicleTrackdir(last));
    02632       assert(trackdir != INVALID_TRACKDIR);
    02633       assert(trackdir_rev != INVALID_TRACKDIR);
    02634
    02635       ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, &fstd, TRANSPORT_RAIL, 0, v->owner, v->u.rail.compatible_railtypes);
    02636       if (ftd.best_bird_dist != 0) {
    02637         /* We didn't find anything, just keep on going straight ahead */
    02638         reverse_best = false;
    02639       } else {
    02640         if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)) {
    02641           reverse_best = true;
    02642         } else {
    02643           reverse_best = false;
    02644         }
    02645       }
    02646     } break;
    02647
    02648     default:
    02649     case VPF_NTP: { /* NTP */
    02650       int best_track = -1;
    02651       uint reverse = 0;
    02652       uint best_bird_dist  = 0;
    02653       uint best_track_dist = 0;
    02654
    02655       for (;;) {
    02656         fd.best_bird_dist = UINT_MAX;
    02657         fd.best_track_dist = UINT_MAX;
    02658
    02659         NewTrainPathfind(v->tile, v->dest_tile, v->u.rail.compatible_railtypes, (DiagDirection)(reverse ^ i), (NTPEnumProc*)NtpCallbFindStation, &fd);
    02660
    02661         if (best_track != -1) {
    02662           if (best_bird_dist != 0) {
    02663             if (fd.best_bird_dist != 0) {
    02664               /* neither reached the destination, pick the one with the smallest bird dist */
    02665               if (fd.best_bird_dist > best_bird_dist) goto bad;
    02666               if (fd.best_bird_dist < best_bird_dist) goto good;
    02667             } else {
    02668               /* we found the destination for the first time */
    02669               goto good;
    02670             }
    02671           } else {
    02672             if (fd.best_bird_dist != 0) {
    02673               /* didn't find destination, but we've found the destination previously */
    02674               goto bad;
    02675             } else {
    02676               /* both old & new reached the destination, compare track length */
    02677               if (fd.best_track_dist > best_track_dist) goto bad;
    02678               if (fd.best_track_dist < best_track_dist) goto good;
    02679             }
    02680           }
    02681
    02682           /* if we reach this position, there's two paths of equal value so far.
    02683            * pick one randomly. */
    02684           int r = GB(Random(), 0, 8);
    02685           if (_pick_track_table[i] == (v->direction & 3)) r += 80;
    02686           if (_pick_track_table[best_track] == (v->direction & 3)) r -= 80;
    02687           if (r <= 127) goto bad;
    02688         }
    02689 good:;
    02690         best_track = i;
    02691         best_bird_dist = fd.best_bird_dist;
    02692         best_track_dist = fd.best_track_dist;
    02693         reverse_best = reverse;
    02694 bad:;
    02695         if (reverse != 0) break;
    02696         reverse = 2;
    02697       }
    02698     } break;
    02699   }
    02700
    02701   return reverse_best != 0;
    02702 }
    02703
    02704 static bool ProcessTrainOrder(Vehicle *v)
    02705 {
    02706   switch (v->current_order.type) {
    02707     case OT_GOTO_DEPOT:
    02708       if (!(v->current_order.flags & OFB_PART_OF_ORDERS)) return false;
    02709       if ((v->current_order.flags & OFB_SERVICE_IF_NEEDED) &&
    02710           !v->NeedsServicing()) {
    02711         UpdateVehicleTimetable(v, true);
    02712         v->cur_order_index++;
    02713       }
    02714       break;
    02715
    02716     case OT_LOADING:
    02717     case OT_LEAVESTATION:
    02718       return false;
    02719
    02720     default: break;
    02721   }
    02722
    02730   bool may_reverse = v->current_order.type == OT_NOTHING;
    02731
    02732   /* check if we've reached the waypoint? */
    02733   if (v->current_order.type == OT_GOTO_WAYPOINT && v->tile == v->dest_tile) {
    02734     UpdateVehicleTimetable(v, true);
    02735     v->cur_order_index++;
    02736   }
    02737
    02738   /* check if we've reached a non-stop station while TTDPatch nonstop is enabled.. */
    02739   if (_patches.new_nonstop &&
    02740       v->current_order.flags & OFB_NON_STOP &&
    02741       IsTileType(v->tile, MP_STATION) &&
    02742       v->current_order.dest == GetStationIndex(v->tile)) {
    02743     UpdateVehicleTimetable(v, true);
    02744     v->cur_order_index++;
    02745   }
    02746
    02747   /* Get the current order */
    02748   if (v->cur_order_index >= v->num_orders) v->cur_order_index = 0;
    02749
    02750   const Order *order = GetVehicleOrder(v, v->cur_order_index);
    02751
    02752   /* If no order, do nothing. */
    02753   if (order == NULL) {
    02754     v->current_order.Free();
    02755     v->dest_tile = 0;
    02756     return false;
    02757   }
    02758
    02759   /* If it is unchanged, keep it. */
    02760   if (order->type  == v->current_order.type &&
    02761       order->flags == v->current_order.flags &&
    02762       order->dest  == v->current_order.dest)
    02763     return false;
    02764
    02765   /* Otherwise set it, and determine the destination tile. */
    02766   v->current_order = *order;
    02767
    02768   v->dest_tile = 0;
    02769
    02770   InvalidateVehicleOrder(v);
    02771
    02772   switch (order->type) {
    02773     case OT_GOTO_STATION:
    02774       if (order->dest == v->last_station_visited)
    02775         v->last_station_visited = INVALID_STATION;
    02776       v->dest_tile = GetStation(order->dest)->xy;
    02777       break;
    02778
    02779     case OT_GOTO_DEPOT:
    02780       v->dest_tile = GetDepot(order->dest)->xy;
    02781       break;
    02782
    02783     case OT_GOTO_WAYPOINT:
    02784       v->dest_tile = GetWaypoint(order->dest)->xy;
    02785       break;
    02786
    02787     default:
    02788       return false;
    02789   }
    02790
    02791   return may_reverse && CheckReverseTrain(v);
    02792 }
    02793
    02794 void Train::MarkDirty()
    02795 {
    02796   Vehicle *v = this;
    02797   do {
    02798     v->cur_image = v->GetImage(v->direction);
    02799     MarkSingleVehicleDirty(v);
    02800   } while ((v = v->Next()) != NULL);
    02801
    02802   /* need to update acceleration and cached values since the goods on the train changed. */
    02803   TrainCargoChanged(this);
    02804   UpdateTrainAcceleration(this);
    02805 }
    02806
    02807 static int UpdateTrainSpeed(Vehicle *v)
    02808 {
    02809   uint accel;
    02810
    02811   if (v->vehstatus & VS_STOPPED || HasBit(v->u.rail.flags, VRF_REVERSING)) {
    02812     if (_patches.realistic_acceleration) {
    02813       accel = GetTrainAcceleration(v, AM_BRAKE) * 2;
    02814     } else {
    02815       accel = v->acceleration * -2;
    02816     }
    02817   } else {
    02818     if (_patches.realistic_acceleration) {
    02819       accel = GetTrainAcceleration(v, AM_ACCEL);
    02820     } else {
    02821       accel = v->acceleration;
    02822     }
    02823   }
    02824
    02825   uint spd = v->subspeed + accel * 2;
    02826   v->subspeed = (byte)spd;
    02827   {
    02828     int tempmax = v->max_speed;
    02829     if (v->cur_speed > v->max_speed)
    02830       tempmax = v->cur_speed - (v->cur_speed / 10) - 1;
    02831     v->cur_speed = spd = Clamp(v->cur_speed + ((int)spd >> 8), 0, tempmax);
    02832   }
    02833
    02834   if (!(v->direction & 1)) spd = spd * 3 >> 2;
    02835
    02836   spd += v->progress;
    02837   v->progress = (byte)spd;
    02838   return (spd >> 8);
    02839 }
    02840
    02841 static void TrainEnterStation(Vehicle *v, StationID station)
    02842 {
    02843   v->last_station_visited = station;
    02844
    02845   /* check if a train ever visited this station before */
    02846   Station *st = GetStation(station);
    02847   if (!(st->had_vehicle_of_type & HVOT_TRAIN)) {
    02848     st->had_vehicle_of_type |= HVOT_TRAIN;
    02849     SetDParam(0, st->index);
    02850     uint32 flags = v->owner == _local_player ?
    02851       NEWS_FLAGS(NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ARRIVAL_PLAYER, 0) :
    02852       NEWS_FLAGS(NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ARRIVAL_OTHER,  0);
    02853     AddNewsItem(
    02854       STR_8801_CITIZENS_CELEBRATE_FIRST,
    02855       flags,
    02856       v->index,
    02857       0
    02858     );
    02859   }
    02860
    02861   v->BeginLoading();
    02862   v->current_order.dest = 0;
    02863 }
    02864
    02865 static byte AfterSetTrainPos(Vehicle *v, bool new_tile)
    02866 {
    02867   byte old_z = v->z_pos;
    02868   v->z_pos = GetSlopeZ(v->x_pos, v->y_pos);
    02869
    02870   if (new_tile) {
    02871     ClrBit(v->u.rail.flags, VRF_GOINGUP);
    02872     ClrBit(v->u.rail.flags, VRF_GOINGDOWN);
    02873
    02874     if (v->u.rail.track == TRACK_BIT_X || v->u.rail.track == TRACK_BIT_Y) {
    02875       /* Any track that isn't TRACK_BIT_X or TRACK_BIT_Y cannot be sloped.
    02876        * To check whether the current tile is sloped, and in which
    02877        * direction it is sloped, we get the 'z' at the center of
    02878        * the tile (middle_z) and the edge of the tile (old_z),
    02879        * which we then can compare. */
    02880       static const int HALF_TILE_SIZE = TILE_SIZE / 2;
    02881       static const int INV_TILE_SIZE_MASK = ~(TILE_SIZE - 1);
    02882
    02883       byte middle_z = GetSlopeZ((v->x_pos & INV_TILE_SIZE_MASK) | HALF_TILE_SIZE, (v->y_pos & INV_TILE_SIZE_MASK) | HALF_TILE_SIZE);
    02884
    02885       /* For some reason tunnel tiles are always given as sloped :(
    02886        * But they are not sloped... */
    02887       if (middle_z != v->z_pos && !IsTunnelTile(TileVirtXY(v->x_pos, v->y_pos))) {
    02888         SetBit(v->u.rail.flags, (middle_z > old_z) ? VRF_GOINGUP : VRF_GOINGDOWN);
    02889       }
    02890     }
    02891   }
    02892
    02893   VehiclePositionChanged(v);
    02894   EndVehicleMove(v);
    02895   return old_z;
    02896 }
    02897
    02898 static const Direction _new_vehicle_direction_table[11] = {
    02899   DIR_N , DIR_NW, DIR_W , INVALID_DIR,
    02900   DIR_NE, DIR_N , DIR_SW, INVALID_DIR,
    02901   DIR_E , DIR_SE, DIR_S
    02902 };
    02903
    02904 static inline Direction GetNewVehicleDirectionByTile(TileIndex new_tile, TileIndex old_tile)
    02905 {
    02906   uint offs = (TileY(new_tile) - TileY(old_tile) + 1) * 4 +
    02907               TileX(new_tile) - TileX(old_tile) + 1;
    02908   assert(offs < 11);
    02909   return _new_vehicle_direction_table[offs];
    02910 }
    02911
    02912 static inline int GetDirectionToVehicle(const Vehicle *v, int x, int y)
    02913 {
    02914   byte offs;
    02915
    02916   x -= v->x_pos;
    02917   if (x >= 0) {
    02918     offs = (x > 2) ? 0 : 1;
    02919   } else {
    02920     offs = (x < -2) ? 2 : 1;
    02921   }
    02922
    02923   y -= v->y_pos;
    02924   if (y >= 0) {
    02925     offs += ((y > 2) ? 0 : 1) * 4;
    02926   } else {
    02927     offs += ((y < -2) ? 2 : 1) * 4;
    02928   }
    02929
    02930   assert(offs < 11);
    02931   return _new_vehicle_direction_table[offs];
    02932 }
    02933
    02934 /* Check if the vehicle is compatible with the specified tile */
    02935 static inline bool CheckCompatibleRail(const Vehicle *v, TileIndex tile)
    02936 {
    02937   return
    02938     IsTileOwner(tile, v->owner) && (
    02939       !IsFrontEngine(v) ||
    02940       HasBit(v->u.rail.compatible_railtypes, GetRailType(tile))
    02941     );
    02942 }
    02943
    02944 struct RailtypeSlowdownParams {
    02945   byte small_turn, large_turn;
    02946   byte z_up; // fraction to remove when moving up
    02947   byte z_down; // fraction to remove when moving down
    02948 };
    02949
    02950 static const RailtypeSlowdownParams _railtype_slowdown[] = {
    02951   // normal accel
    02952   {256 / 4, 256 / 2, 256 / 4, 2},
    02953   {256 / 4, 256 / 2, 256 / 4, 2},
    02954   {256 / 4, 256 / 2, 256 / 4, 2},
    02955   {0,       256 / 2, 256 / 4, 2},
    02956 };
    02957
    02959 static inline void AffectSpeedByDirChange(Vehicle* v, Direction new_dir)
    02960 {
    02961   if (_patches.realistic_acceleration) return;
    02962
    02963   DirDiff diff = DirDifference(v->direction, new_dir);
    02964   if (diff == DIRDIFF_SAME) return;
    02965
    02966   const RailtypeSlowdownParams *rsp = &_railtype_slowdown[v->u.rail.railtype];
    02967   v->cur_speed -= (diff == DIRDIFF_45RIGHT || diff == DIRDIFF_45LEFT ? rsp->small_turn : rsp->large_turn) * v->cur_speed >> 8;
    02968 }
    02969
    02971 static inline void AffectSpeedByZChange(Vehicle *v, byte old_z)
    02972 {
    02973   if (old_z == v->z_pos || _patches.realistic_acceleration) return;
    02974
    02975   const RailtypeSlowdownParams *rsp = &_railtype_slowdown[v->u.rail.railtype];
    02976
    02977   if (old_z < v->z_pos) {
    02978     v->cur_speed -= (v->cur_speed * rsp->z_up >> 8);
    02979   } else {
    02980     uint16 spd = v->cur_speed + rsp->z_down;
    02981     if (spd <= v->max_speed) v->cur_speed = spd;
    02982   }
    02983 }
    02984
    02985 static const DiagDirection _otherside_signal_directions[] = {
    02986   DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE, INVALID_DIAGDIR, INVALID_DIAGDIR,
    02987   DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE
    02988 };
    02989
    02990 static void TrainMovedChangeSignals(TileIndex tile, DiagDirection dir)
    02991 {
    02992   if (IsTileType(tile, MP_RAILWAY) &&
    02993       GetRailTileType(tile) == RAIL_TILE_SIGNALS) {
    02994     uint i = FindFirstBit2x64(GetTrackBits(tile) * 0x101 & _reachable_tracks[dir]);
    02995     UpdateSignalsOnSegment(tile, _otherside_signal_directions[i], GetTileOwner(tile));
    02996   }
    02997 }
    02998
    02999
    03000 static void SetVehicleCrashed(Vehicle *v)
    03001 {
    03002   if (v->u.rail.crash_anim_pos != 0) return;
    03003
    03004   /* we may need to update crossing we were approaching */
    03005   TileIndex crossing = TrainApproachingCrossingTile(v);
    03006
    03007   v->u.rail.crash_anim_pos++;
    03008
    03009   InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
    03010   InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
    03011
    03012   if (v->u.rail.track == TRACK_BIT_DEPOT) {
    03013     InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
    03014   }
    03015
    03016   RebuildVehicleLists();
    03017
    03018   BEGIN_ENUM_WAGONS(v)
    03019     v->vehstatus |= VS_CRASHED;
    03020     MarkSingleVehicleDirty(v);
    03021   END_ENUM_WAGONS(v)
    03022
    03023   /* must be updated after the train has been marked crashed */
    03024   if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing);
    03025 }
    03026
    03027 static uint CountPassengersInTrain(const Vehicle* v)
    03028 {
    03029   uint num = 0;
    03030   BEGIN_ENUM_WAGONS(v)
    03031     if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) num += v->cargo.Count();
    03032   END_ENUM_WAGONS(v)
    03033   return num;
    03034 }
    03035
    03036 struct TrainCollideChecker {
    03037   Vehicle *v;
    03038   uint num;
    03039 };
    03040
    03041 static void *FindTrainCollideEnum(Vehicle *v, void *data)
    03042 {
    03043   TrainCollideChecker* tcc = (TrainCollideChecker*)data;
    03044
    03045   if (v->type != VEH_TRAIN) return NULL;
    03046
    03047   /* get first vehicle now to make most usual checks faster */
    03048   Vehicle *coll = v->First();
    03049
    03050   /* can't collide with own wagons && can't crash in depot && the same height level */
    03051   if (coll != tcc->v && v->u.rail.track != TRACK_BIT_DEPOT && abs(v->z_pos - tcc->v->z_pos) < 6) {
    03052     int x_diff = v->x_pos - tcc->v->x_pos;
    03053     int y_diff = v->y_pos - tcc->v->y_pos;
    03054
    03055     /* needed to disable possible crash of competitor train in station by building diagonal track at its end */
    03056     if (x_diff * x_diff + y_diff * y_diff > 25) return NULL;
    03057
    03058     if (!(tcc->v->vehstatus & VS_CRASHED)) {
    03059       /* two drivers + passengers killed in train tcc->v (if it was not crashed already) */
    03060       tcc->num += 2 + CountPassengersInTrain(tcc->v);
    03061       SetVehicleCrashed(tcc->v);
    03062     }
    03063
    03064     if (!(coll->vehstatus & VS_CRASHED)) {
    03065       /* two drivers + passengers killed in train coll (if it was not crashed already) */
    03066       tcc->num += 2 + CountPassengersInTrain(coll);
    03067       SetVehicleCrashed(coll);
    03068     }
    03069   }
    03070
    03071   return NULL;
    03072 }
    03073
    03080 static void CheckTrainCollision(Vehicle *v)
    03081 {
    03082   /* can't collide in depot */
    03083   if (v->u.rail.track == TRACK_BIT_DEPOT) return;
    03084
    03085   assert(v->u.rail.track == TRACK_BIT_WORMHOLE || TileVirtXY(v->x_pos, v->y_pos) == v->tile);
    03086
    03087   TrainCollideChecker tcc;
    03088   tcc.v = v;
    03089   tcc.num = 0;
    03090
    03091   /* find colliding vehicles */
    03092   if (v->u.rail.track == TRACK_BIT_WORMHOLE) {
    03093     FindVehicleOnPos(v->tile, &tcc, FindTrainCollideEnum);
    03094     FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &tcc, FindTrainCollideEnum);
    03095   } else {
    03096     FindVehicleOnPosXY(v->x_pos, v->y_pos, &tcc, FindTrainCollideEnum);
    03097   }
    03098
    03099   /* any dead -> no crash */
    03100   if (tcc.num == 0) return;
    03101
    03102   SetDParam(0, tcc.num);
    03103   AddNewsItem(STR_8868_TRAIN_CRASH_DIE_IN_FIREBALL,
    03104     NEWS_FLAGS(NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, 0),
    03105     v->index,
    03106     0
    03107   );
    03108
    03109   ModifyStationRatingAround(v->tile, v->owner, -160, 30);
    03110   SndPlayVehicleFx(SND_13_BIG_CRASH, v);
    03111 }
    03112
    03113 static void *CheckVehicleAtSignal(Vehicle *v, void *data)
    03114 {
    03115   DiagDirection exitdir = *(DiagDirection *)data;
    03116
    03117   /* front engine of a train, not inside wormhole or depot, not crashed */
    03118   if (v->type == VEH_TRAIN && IsFrontEngine(v) && (v->u.rail.track & TRACK_BIT_MASK) != 0 && !(v->vehstatus & VS_CRASHED)) {
    03119     if (v->cur_speed <= 5 && TrainExitDir(v->direction, v->u.rail.track) == exitdir) return v;
    03120   }
    03121
    03122   return NULL;
    03123 }
    03124
    03125 static void TrainController(Vehicle *v, Vehicle *nomove, bool update_image)
    03126 {
    03127   Vehicle *prev;
    03128
    03129   /* For every vehicle after and including the given vehicle */
    03130   for (prev = v->Previous(); v != nomove; prev = v, v = v->Next()) {
    03131     DiagDirection enterdir = DIAGDIR_BEGIN;
    03132     bool update_signals_crossing = false; // will we update signals or crossing state?
    03133     BeginVehicleMove(v);
    03134
    03135     GetNewVehiclePosResult gp = GetNewVehiclePos(v);
    03136     if (v->u.rail.track != TRACK_BIT_WORMHOLE) {
    03137       /* Not inside tunnel */
    03138       if (gp.old_tile == gp.new_tile) {
    03139         /* Staying in the old tile */
    03140         if (v->u.rail.track == TRACK_BIT_DEPOT) {
    03141           /* Inside depot */
    03142           gp.x = v->x_pos;
    03143           gp.y = v->y_pos;
    03144         } else {
    03145           /* Not inside depot */
    03146
    03147           if (IsFrontEngine(v) && !TrainCheckIfLineEnds(v)) return;
    03148
    03149           uint32 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
    03150           if (HasBit(r, VETS_CANNOT_ENTER)) {
    03151             goto invalid_rail;
    03152           }
    03153           if (HasBit(r, VETS_ENTERED_STATION)) {
    03154             TrainEnterStation(v, r >> VETS_STATION_ID_OFFSET);
    03155             return;
    03156           }
    03157
    03158           if (v->current_order.type == OT_LEAVESTATION) {
    03159             v->current_order.Free();
    03160             InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
    03161           }
    03162         }
    03163       } else {
    03164         /* A new tile is about to be entered. */
    03165
    03166         /* Determine what direction we're entering the new tile from */
    03167         Direction dir = GetNewVehicleDirectionByTile(gp.new_tile, gp.old_tile);
    03168         enterdir = DirToDiagDir(dir);
    03169         assert(IsValidDiagDirection(enterdir));
    03170
    03171         /* Get the status of the tracks in the new tile and mask
    03172          * away the bits that aren't reachable. */
    03173         TrackStatus ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL, 0, ReverseDiagDir(enterdir)) & _reachable_tracks[enterdir];
    03174         TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts);
    03175         TrackBits red_signals = TrackdirBitsToTrackBits(TrackStatusToRedSignals(ts));
    03176
    03177         TrackBits bits = TrackdirBitsToTrackBits(trackdirbits);
    03178         if (_patches.pathfinder_for_trains != VPF_NTP && _patches.forbid_90_deg && prev == NULL) {
    03179           /* We allow wagons to make 90 deg turns, because forbid_90_deg
    03180            * can be switched on halfway a turn */
    03181           bits &= ~TrackCrossesTracks(FindFirstTrack(v->u.rail.track));
    03182         }
    03183
    03184         if (bits == TRACK_BIT_NONE) goto invalid_rail;
    03185
    03186         /* Check if the new tile contrains tracks that are compatible
    03187          * with the current train, if not, bail out. */
    03188         if (!CheckCompatibleRail(v, gp.new_tile)) goto invalid_rail;
    03189
    03190         TrackBits chosen_track;
    03191         if (prev == NULL) {
    03192           /* Currently the locomotive is active. Determine which one of the
    03193            * available tracks to choose */
    03194           chosen_track = TrackToTrackBits(ChooseTrainTrack(v, gp.new_tile, enterdir, bits));
    03195           assert(chosen_track & bits);
    03196
    03197           /* Check if it's a red signal and that force proceed is not clicked. */
    03198           if (red_signals & chosen_track && v->u.rail.force_proceed == 0) {
    03199             /* In front of a red signal */
    03200             Trackdir i = FindFirstTrackdir(trackdirbits);
    03201
    03202             if (!HasSignalOnTrackdir(gp.new_tile, ReverseTrackdir(i))) {
    03203               v->cur_speed = 0;
    03204               v->subspeed = 0;
    03205               v->progress = 255 - 100;
    03206               if (++v->load_unload_time_rem < _patches.wait_oneway_signal * 20) return;
    03207             } else if (HasSignalOnTrackdir(gp.new_tile, i)) {
    03208               v->cur_speed = 0;
    03209               v->subspeed = 0;
    03210               v->progress = 255 - 10;
    03211               if (++v->load_unload_time_rem < _patches.wait_twoway_signal * 73) {
    03212                 DiagDirection exitdir = TrackdirToExitdir(i);
    03213                 TileIndex o_tile = TileAddByDiagDir(gp.new_tile, exitdir);
    03214
    03215                 exitdir = ReverseDiagDir(exitdir);
    03216
    03217                 /* check if a train is waiting on the other side */
    03218                 if (!HasVehicleOnPos(o_tile, &exitdir, &CheckVehicleAtSignal)) return;
    03219               }
    03220             }
    03221             goto reverse_train_direction;
    03222           }
    03223         } else {
    03224           static const TrackBits _matching_tracks[8] = {
    03225               TRACK_BIT_LEFT  | TRACK_BIT_RIGHT, TRACK_BIT_X,
    03226               TRACK_BIT_UPPER | TRACK_BIT_LOWER, TRACK_BIT_Y,
    03227               TRACK_BIT_LEFT  | TRACK_BIT_RIGHT, TRACK_BIT_X,
    03228               TRACK_BIT_UPPER | TRACK_BIT_LOWER, TRACK_BIT_Y
    03229           };
    03230
    03231           /* The wagon is active, simply follow the prev vehicle. */
    03232           chosen_track = (TrackBits)(byte)(_matching_tracks[GetDirectionToVehicle(prev, gp.x, gp.y)] & bits);
    03233         }
    03234
    03235         /* Make sure chosen track is a valid track */
    03236         assert(
    03237             chosen_track == TRACK_BIT_X     || chosen_track == TRACK_BIT_Y ||
    03238             chosen_track == TRACK_BIT_UPPER || chosen_track == TRACK_BIT_LOWER ||
    03239             chosen_track == TRACK_BIT_LEFT  || chosen_track == TRACK_BIT_RIGHT);
    03240
    03241         /* Update XY to reflect the entrance to the new tile, and select the direction to use */
    03242         const byte *b = _initial_tile_subcoord[FIND_FIRST_BIT(chosen_track)][enterdir];
    03243         gp.x = (gp.x & ~0xF) | b[0];
    03244         gp.y = (gp.y & ~0xF) | b[1];
    03245         Direction chosen_dir = (Direction)b[2];
    03246
    03247         /* Call the landscape function and tell it that the vehicle entered the tile */
    03248         uint32 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
    03249         if (HasBit(r, VETS_CANNOT_ENTER)) {
    03250           goto invalid_rail;
    03251         }
    03252
    03253         if (IsFrontEngine(v)) v->load_unload_time_rem = 0;
    03254
    03255         if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
    03256           v->tile = gp.new_tile;
    03257
    03258           if (GetTileRailType(gp.new_tile) != GetTileRailType(gp.old_tile)) {
    03259             TrainPowerChanged(v->First());
    03260           }
    03261
    03262           v->u.rail.track = chosen_track;
    03263           assert(v->u.rail.track);
    03264         }
    03265
    03266         /* We need to update signal status, but after the vehicle position hash
    03267          * has been updated by AfterSetTrainPos() */
    03268         update_signals_crossing = true;
    03269
    03270         if (prev == NULL) AffectSpeedByDirChange(v, chosen_dir);
    03271
    03272         v->direction = chosen_dir;
    03273       }
    03274     } else {
    03275       /* In a tunnel or on a bridge
    03276        * - for tunnels, only the part when the vehicle is not visible (part of enter/exit tile too)
    03277        * - for bridges, only the middle part - without the bridge heads */
    03278       if (!(v->vehstatus & VS_HIDDEN)) {
    03279         v->cur_speed =
    03280           min(v->cur_speed, GetBridgeSpec(GetBridgeType(v->tile))->speed);
    03281       }
    03282
    03283       if (!IsTileType(gp.new_tile, MP_TUNNELBRIDGE) || !HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
    03284         v->x_pos = gp.x;
    03285         v->y_pos = gp.y;
    03286         VehiclePositionChanged(v);
    03287         if (!(v->vehstatus & VS_HIDDEN)) EndVehicleMove(v);
    03288         continue;
    03289       }
    03290     }
    03291
    03292     /* update image of train, as well as delta XY */
    03293     v->UpdateDeltaXY(v->direction);
    03294     if (update_image) v->cur_image = v->GetImage(v->direction);
    03295
    03296     v->x_pos = gp.x;
    03297     v->y_pos = gp.y;
    03298
    03299     /* update the Z position of the vehicle */
    03300     byte old_z = AfterSetTrainPos(v, (gp.new_tile != gp.old_tile));
    03301
    03302     if (prev == NULL) {
    03303       /* This is the first vehicle in the train */
    03304       AffectSpeedByZChange(v, old_z);
    03305     }
    03306
    03307     if (update_signals_crossing) {
    03308       if (IsFrontEngine(v)) TrainMovedChangeSignals(gp.new_tile, enterdir);
    03309
    03310       /* Signals can only change when the first
    03311        * (above) or the last vehicle moves. */
    03312       if (v->Next() == NULL) {
    03313         TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir));
    03314         if (IsLevelCrossingTile(gp.old_tile)) UpdateLevelCrossing(gp.old_tile);
    03315       }
    03316     }
    03317   }
    03318   return;
    03319
    03320 invalid_rail:
    03321   /* We've reached end of line?? */
    03322   if (prev != NULL) error("!Disconnecting train");
    03323
    03324 reverse_train_direction:
    03325   v->load_unload_time_rem = 0;
    03326   v->cur_speed = 0;
    03327   v->subspeed = 0;
    03328   ReverseTrainDirection(v);
    03329 }
    03330
    03338 static void DeleteLastWagon(Vehicle *v)
    03339 {
    03340   Vehicle *first = v->First();
    03341
    03342   /* Go to the last wagon and delete the link pointing there
    03343    * *u is then the one-before-last wagon, and *v the last
    03344    * one which will physicially be removed */
    03345   Vehicle *u = v;
    03346   for (; v->Next() != NULL; v = v->Next()) u = v;
    03347   u->SetNext(NULL);
    03348
    03349   if (first == v) {
    03350     /* Removing front vehicle (the last to go) */
    03351     DeleteWindowById(WC_VEHICLE_VIEW, v->index);
    03352     InvalidateWindow(WC_COMPANY, v->owner);
    03353   } else {
    03354     /* Recalculate cached train properties */
    03355     TrainConsistChanged(first, false);
    03356     /* Update the depot window if the first vehicle is in depot -
    03357      * if v == first, then it is updated in PreDestructor() */
    03358     if (first->u.rail.track == TRACK_BIT_DEPOT) {
    03359       InvalidateWindow(WC_VEHICLE_DEPOT, first->tile);
    03360     }
    03361   }
    03362
    03363   RebuildVehicleLists();
    03364
    03365   MarkSingleVehicleDirty(v);
    03366
    03367   /* 'v' shouldn't be accessed after it has been deleted */
    03368   TrackBits track = v->u.rail.track;
    03369   TileIndex tile = v->tile;
    03370   Owner owner = v->owner;
    03371
    03372   delete v;
    03373   v = NULL; // make sure nobody will won't try to read 'v' anymore
    03374
    03375   /* check if the wagon was on a road/rail-crossing */
    03376   if (IsLevelCrossingTile(tile)) UpdateLevelCrossing(tile);
    03377
    03378   /* Update signals */
    03379   if (IsTileType(tile, MP_TUNNELBRIDGE) || IsTileDepotType(tile, TRANSPORT_RAIL)) {
    03380     UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, owner);
    03381   } else {
    03382     SetSignalsOnBothDir(tile, (Track)(FIND_FIRST_BIT(track)), owner);
    03383   }
    03384 }
    03385
    03386 static void ChangeTrainDirRandomly(Vehicle *v)
    03387 {
    03388   static const DirDiff delta[] = {
    03389     DIRDIFF_45LEFT, DIRDIFF_SAME, DIRDIFF_SAME, DIRDIFF_45RIGHT
    03390   };
    03391
    03392   do {
    03393     /* We don't need to twist around vehicles if they're not visible */
    03394     if (!(v->vehstatus & VS_HIDDEN)) {
    03395       v->direction = ChangeDir(v->direction, delta[GB(Random(), 0, 2)]);
    03396       BeginVehicleMove(v);
    03397       v->UpdateDeltaXY(v->direction);
    03398       v->cur_image = v->GetImage(v->direction);
    03399       /* Refrain from updating the z position of the vehicle when on
    03400          a bridge, because AfterSetTrainPos will put the vehicle under
    03401          the bridge in that case */
    03402       if (v->u.rail.track != TRACK_BIT_WORMHOLE) AfterSetTrainPos(v, false);
    03403     }
    03404   } while ((v = v->Next()) != NULL);
    03405 }
    03406
    03407 static void HandleCrashedTrain(Vehicle *v)
    03408 {
    03409   int state = ++v->u.rail.crash_anim_pos;
    03410
    03411   if (state == 4 && !(v->vehstatus & VS_HIDDEN)) {
    03412     CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
    03413   }
    03414
    03415   uint32 r;
    03416   if (state <= 200 && Chance16R(1, 7, r)) {
    03417     int index = (r * 10 >> 16);
    03418
    03419     Vehicle *u = v;
    03420     do {
    03421       if (--index < 0) {
    03422         r = Random();
    03423
    03424         CreateEffectVehicleRel(u,
    03425           GB(r,  8, 3) + 2,
    03426           GB(r, 16, 3) + 2,
    03427           GB(r,  0, 3) + 5,
    03428           EV_EXPLOSION_SMALL);
    03429         break;
    03430       }
    03431     } while ((u = u->Next()) != NULL);
    03432   }
    03433
    03434   if (state <= 240 && !(v->tick_counter & 3)) ChangeTrainDirRandomly(v);
    03435
    03436   if (state >= 4440 && !(v->tick_counter&0x1F)) {
    03437     DeleteLastWagon(v);
    03438     InvalidateWindow(WC_REPLACE_VEHICLE, (v->group_id << 16) | VEH_TRAIN);
    03439   }
    03440 }
    03441
    03442 static void HandleBrokenTrain(Vehicle *v)
    03443 {
    03444   if (v->breakdown_ctr != 1) {
    03445     v->breakdown_ctr = 1;
    03446     v->cur_speed = 0;
    03447
    03448     if (v->breakdowns_since_last_service != 255)
    03449       v->breakdowns_since_last_service++;
    03450
    03451     InvalidateWindow(WC_VEHICLE_VIEW, v->index);
    03452     InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
    03453
    03454     if (!PlayVehicleSound(v, VSE_BREAKDOWN)) {
    03455       SndPlayVehicleFx((_opt.landscape != LT_TOYLAND) ?
    03456         SND_10_TRAIN_BREAKDOWN : SND_3A_COMEDY_BREAKDOWN_2, v);
    03457     }
    03458
    03459     if (!(v->vehstatus & VS_HIDDEN)) {
    03460       Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE);
    03461       if (u != NULL) u->u.special.animation_state = v->breakdown_delay * 2;
    03462     }
    03463   }
    03464
    03465   if (!(v->tick_counter & 3)) {
    03466     if (!--v->breakdown_delay) {
    03467       v->breakdown_ctr = 0;
    03468       InvalidateWindow(WC_VEHICLE_VIEW, v->index);
    03469     }
    03470   }
    03471 }
    03472
    03474 static const uint16 _breakdown_speeds[16] = {
    03475   225, 210, 195, 180, 165, 150, 135, 120, 105, 90, 75, 60, 45, 30, 15, 15
    03476 };
    03477
    03478
    03486 static bool TrainApproachingLineEnd(Vehicle *v, bool signal)
    03487 {
    03488   /* Calc position within the current tile */
    03489   uint x = v->x_pos & 0xF;
    03490   uint y = v->y_pos & 0xF;
    03491
    03492   /* for diagonal directions, 'x' will be 0..15 -
    03493    * for other directions, it will be 1, 3, 5, ..., 15 */
    03494   switch (v->direction) {
    03495     case DIR_N : x = ~x + ~y + 25; break;
    03496     case DIR_NW: x = y;            /* FALLTHROUGH */
    03497     case DIR_NE: x = ~x + 16;      break;
    03498     case DIR_E : x = ~x + y + 9;   break;
    03499     case DIR_SE: x = y;            break;
    03500     case DIR_S : x = x + y - 7;    break;
    03501     case DIR_W : x = ~y + x + 9;   break;
    03502     default: break;
    03503   }
    03504
    03505   /* do not reverse when approaching red signal */
    03506   if (!signal && x + 4 >= TILE_SIZE) {
    03507     /* we are too near the tile end, reverse now */
    03508     v->cur_speed = 0;
    03509     ReverseTrainDirection(v);
    03510     return false;
    03511   }
    03512
    03513   /* slow down */
    03514   v->vehstatus |= VS_TRAIN_SLOWING;
    03515   uint16 break_speed = _breakdown_speeds[x & 0xF];
    03516   if (break_speed < v->cur_speed) v->cur_speed = break_speed;
    03517
    03518   return true;
    03519 }
    03520
    03521
    03527 static bool TrainCanLeaveTile(const Vehicle *v)
    03528 {
    03529   /* Exit if inside a tunnel/bridge or a depot */
    03530   if (v->u.rail.track == TRACK_BIT_WORMHOLE || v->u.rail.track == TRACK_BIT_DEPOT) return false;
    03531
    03532   TileIndex tile = v->tile;
    03533
    03534   /* entering a tunnel/bridge? */
    03535   if (IsTileType(tile, MP_TUNNELBRIDGE)) {
    03536     DiagDirection dir = GetTunnelBridgeDirection(tile);
    03537     if (DiagDirToDir(dir) == v->direction) return false;
    03538   }
    03539
    03540   /* entering a depot? */
    03541   if (IsTileDepotType(tile, TRANSPORT_RAIL)) {
    03542     DiagDirection dir = ReverseDiagDir(GetRailDepotDirection(tile));
    03543     if (DiagDirToDir(dir) == v->direction) return false;
    03544   }
    03545
    03546   return true;
    03547 }
    03548
    03549
    03557 static TileIndex TrainApproachingCrossingTile(const Vehicle *v)
    03558 {
    03559   assert(IsFrontEngine(v));
    03560   assert(!(v->vehstatus & VS_CRASHED));
    03561
    03562   if (!TrainCanLeaveTile(v)) return INVALID_TILE;
    03563
    03564   DiagDirection dir = TrainExitDir(v->direction, v->u.rail.track);
    03565   TileIndex tile = v->tile + TileOffsByDiagDir(dir);
    03566
    03567   /* not a crossing || wrong axis || unusable rail (wrong type or owner) */
    03568   if (!IsLevelCrossingTile(tile) || DiagDirToAxis(dir) == GetCrossingRoadAxis(tile) ||
    03569       !CheckCompatibleRail(v, tile)) {
    03570     return INVALID_TILE;
    03571   }
    03572
    03573   return tile;
    03574 }
    03575
    03576
    03583 static bool TrainCheckIfLineEnds(Vehicle *v)
    03584 {
    03585   /* First, handle broken down train */
    03586
    03587   int t = v->breakdown_ctr;
    03588   if (t > 1) {
    03589     v->vehstatus |= VS_TRAIN_SLOWING;
    03590
    03591     uint16 break_speed = _breakdown_speeds[GB(~t, 4, 4)];
    03592     if (break_speed < v->cur_speed) v->cur_speed = break_speed;
    03593   } else {
    03594     v->vehstatus &= ~VS_TRAIN_SLOWING;
    03595   }
    03596
    03597   if (!TrainCanLeaveTile(v)) return true;
    03598
    03599   /* Determine the non-diagonal direction in which we will exit this tile */
    03600   DiagDirection dir = TrainExitDir(v->direction, v->u.rail.track);
    03601   /* Calculate next tile */
    03602   TileIndex tile = v->tile + TileOffsByDiagDir(dir);
    03603
    03604   /* Determine the track status on the next tile */
    03605 ; TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_RAIL, 0, ReverseDiagDir(dir)) & _reachable_tracks[dir];
    03606   TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts);
    03607   TrackdirBits red_signals = TrackStatusToRedSignals(ts);
    03608
    03609   /* We are sure the train is not entering a depot, it is detected above */
    03610
    03611   /* mask unreachable track bits if we are forbidden to do 90deg turns */
    03612   TrackBits bits = TrackdirBitsToTrackBits(trackdirbits);
    03613   if (_patches.pathfinder_for_trains != VPF_NTP && _patches.forbid_90_deg) {
    03614     bits &= ~TrackCrossesTracks(FindFirstTrack(v->u.rail.track));
    03615   }
    03616
    03617   /* no suitable trackbits at all || unusable rail (wrong type or owner) */
    03618   if (bits == TRACK_BIT_NONE || !CheckCompatibleRail(v, tile)) {
    03619     return TrainApproachingLineEnd(v, false);
    03620   }
    03621
    03622   /* approaching red signal */
    03623   if ((trackdirbits & red_signals) != 0) return TrainApproachingLineEnd(v, true);
    03624
    03625   /* approaching a rail/road crossing? then make it red */
    03626   if (IsLevelCrossingTile(tile)) MaybeBarCrossingWithSound(tile);
    03627
    03628   return true;
    03629 }
    03630
    03631
    03632 static void TrainLocoHandler(Vehicle *v, bool mode)
    03633 {
    03634   /* train has crashed? */
    03635   if (v->vehstatus & VS_CRASHED) {
    03636     if (!mode) HandleCrashedTrain(v);
    03637     return;
    03638   }
    03639
    03640   if (v->u.rail.force_proceed != 0) v->u.rail.force_proceed--;
    03641
    03642   /* train is broken down? */
    03643   if (v->breakdown_ctr != 0) {
    03644     if (v->breakdown_ctr <= 2) {
    03645       HandleBrokenTrain(v);
    03646       return;
    03647     }
    03648     if (v->current_order.type != OT_LOADING) v->breakdown_ctr--;
    03649   }
    03650
    03651   if (HasBit(v->u.rail.flags, VRF_REVERSING) && v->cur_speed == 0) {
    03652     ReverseTrainDirection(v);
    03653   }
    03654
    03655   /* exit if train is stopped */
    03656   if (v->vehstatus & VS_STOPPED && v->cur_speed == 0) return;
    03657
    03658   if (ProcessTrainOrder(v)) {
    03659     v->load_unload_time_rem = 0;
    03660     v->cur_speed = 0;
    03661     v->subspeed = 0;
    03662     ReverseTrainDirection(v);
    03663     return;
    03664   }
    03665
    03666   v->HandleLoading(mode);
    03667
    03668   if (v->current_order.type == OT_LOADING) return;
    03669
    03670   if (CheckTrainStayInDepot(v)) return;
    03671
    03672   if (!mode) HandleLocomotiveSmokeCloud(v);
    03673
    03674   int j = UpdateTrainSpeed(v);
    03675
    03676   /* we need to invalidate the widget if we are stopping from 'Stopping 0 km/h' to 'Stopped' */
    03677   if (v->cur_speed == 0 && v->u.rail.last_speed == 0 && v->vehstatus & VS_STOPPED) {
    03678     InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
    03679   }
    03680
    03681   if (j == 0) {
    03682     /* if the vehicle has speed 0, update the last_speed field. */
    03683     if (v->cur_speed != 0) return;
    03684   } else {
    03685     TrainCheckIfLineEnds(v);
    03686
    03687     do {
    03688       TrainController(v, NULL, true);
    03689       CheckTrainCollision(v);
    03690       if (v->cur_speed <= 0x100)
    03691         break;
    03692     } while (--j != 0);
    03693   }
    03694
    03695   SetLastSpeed(v, v->cur_speed);
    03696 }
    03697
    03698
    03699
    03700 Money Train::GetRunningCost() const
    03701 {
    03702   Money cost = 0;
    03703   const Vehicle *v = this;
    03704
    03705   do {
    03706     const RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
    03707
    03708     byte cost_factor = GetVehicleProperty(v, 0x0D, rvi->running_cost);
    03709     if (cost_factor == 0) continue;
    03710
    03711     /* Halve running cost for multiheaded parts */
    03712     if (IsMultiheaded(v)) cost_factor /= 2;
    03713
    03714     cost += cost_factor * GetPriceByIndex(rvi->running_cost_class);
    03715   } while ((v = GetNextVehicle(v)) != NULL);
    03716
    03717   return cost;
    03718 }
    03719
    03720
    03721 void Train::Tick()
    03722 {
    03723   if (_age_cargo_skip_counter == 0) this->cargo.AgeCargo();
    03724
    03725   this->tick_counter++;
    03726
    03727   if (IsFrontEngine(this)) {
    03728     if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
    03729     this->current_order_time++;
    03730
    03731     TrainLocoHandler(this, false);
    03732
    03733     /* make sure vehicle wasn't deleted. */
    03734     if (this->type == VEH_TRAIN && IsFrontEngine(this))
    03735       TrainLocoHandler(this, true);
    03736   } else if (IsFreeWagon(this) && HASBITS(this->vehstatus, VS_CRASHED)) {
    03737     /* Delete flooded standalone wagon chain */
    03738     if (++this->u.rail.crash_anim_pos >= 4400) DeleteVehicleChain(this);
    03739   }
    03740 }
    03741
    03742 #define MAX_ACCEPTABLE_DEPOT_DIST 16
    03743
    03744 static void CheckIfTrainNeedsService(Vehicle *v)
    03745 {
    03746   if (_patches.servint_trains == 0 || !v->NeedsAutomaticServicing()) return;
    03747   if (v->IsInDepot()) {
    03748     VehicleServiceInDepot(v);
    03749     return;
    03750   }
    03751
    03752   TrainFindDepotData tfdd = FindClosestTrainDepot(v, MAX_ACCEPTABLE_DEPOT_DIST);
    03753   /* Only go to the depot if it is not too far out of our way. */
    03754   if (tfdd.best_length == (uint)-1 || tfdd.best_length > MAX_ACCEPTABLE_DEPOT_DIST) {
    03755     if (v->current_order.type == OT_GOTO_DEPOT) {
    03756       /* If we were already heading for a depot but it has
    03757        * suddenly moved farther away, we continue our normal
    03758        * schedule? */
    03759       v->current_order.type = OT_DUMMY;
    03760       v->current_order.flags = 0;
    03761       InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
    03762     }
    03763     return;
    03764   }
    03765
    03766   const Depot* depot = GetDepotByTile(tfdd.tile);
    03767
    03768   if (v->current_order.type == OT_GOTO_DEPOT &&
    03769       v->current_order.dest != depot->index &&
    03770       !Chance16(3, 16)) {
    03771     return;
    03772   }
    03773
    03774   v->current_order.type = OT_GOTO_DEPOT;
    03775   v->current_order.flags = OFB_NON_STOP;
    03776   v->current_order.dest = depot->index;
    03777   v->dest_tile = tfdd.tile;
    03778   InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
    03779 }
    03780
    03781 void Train::OnNewDay()
    03782 {
    03783   if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
    03784
    03785   if (IsFrontEngine(this)) {
    03786     CheckVehicleBreakdown(this);
    03787     AgeVehicle(this);
    03788
    03789     CheckIfTrainNeedsService(this);
    03790
    03791     CheckOrders(this);
    03792
    03793     /* update destination */
    03794     if (this->current_order.type == OT_GOTO_STATION) {
    03795       TileIndex tile = GetStation(this->current_order.dest)->train_tile;
    03796       if (tile != 0) this->dest_tile = tile;
    03797     }
    03798
    03799     if (this->running_ticks != 0) {
    03800       /* running costs */
    03801       CommandCost cost(EXPENSES_TRAIN_RUN, this->GetRunningCost() * this->running_ticks / (364 * DAY_TICKS));
    03802
    03803       this->profit_this_year -= cost.GetCost();
    03804       this->running_ticks = 0;
    03805
    03806       SubtractMoneyFromPlayerFract(this->owner, cost);
    03807
    03808       InvalidateWindow(WC_VEHICLE_DETAILS, this->index);
    03809       InvalidateWindowClasses(WC_TRAINS_LIST);
    03810     }
    03811   } else if (IsTrainEngine(this)) {
    03812     /* Also age engines that aren't front engines */
    03813     AgeVehicle(this);
    03814   }
    03815 }
    03816
    03817 void TrainsYearlyLoop()
    03818 {
    03819   Vehicle *v;
    03820
    03821   FOR_ALL_VEHICLES(v) {
    03822     if (v->type == VEH_TRAIN && IsFrontEngine(v)) {
    03823       /* show warning if train is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */
    03824       if (_patches.train_income_warn && v->owner == _local_player && v->age >= 730 && v->GetDisplayProfitThisYear() < 0) {
    03825         SetDParam(1, v->GetDisplayProfitThisYear());
    03826         SetDParam(0, v->unitnumber);
    03827         AddNewsItem(
    03828           STR_TRAIN_IS_UNPROFITABLE,
    03829           NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0),
    03830           v->index,
    03831           0);
    03832       }
    03833
    03834       v->profit_last_year = v->profit_this_year;
    03835       v->profit_this_year = 0;
    03836       InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
    03837     }
    03838   }
    03839 }
    03840
    03841
    03842 void InitializeTrains()
    03843 {
    03844   _age_cargo_skip_counter = 1;
    03845 }
    03846
    03847 /*
    03848  * Link front and rear multiheaded engines to each other
    03849  * This is done when loading a savegame
    03850  */
    03851 void ConnectMultiheadedTrains()
    03852 {
    03853   Vehicle *v;
    03854
    03855   FOR_ALL_VEHICLES(v) {
    03856     if (v->type == VEH_TRAIN) {
    03857       v->u.rail.other_multiheaded_part = NULL;
    03858     }
    03859   }
    03860
    03861   FOR_ALL_VEHICLES(v) {
    03862     if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) {
    03863       /* Two ways to associate multiheaded parts to each other:
    03864        * sequential-matching: Trains shall be arranged to look like <..>..<..>..<..>..
    03865        * bracket-matching:    Free vehicle chains shall be arranged to look like ..<..<..>..<..>..>..
    03866        *
    03867        * Note: Old savegames might contain chains which do not comply with these rules, e.g.
    03868        *   - the front and read parts have invalid orders
    03869        *   - different engine types might be combined
    03870        *   - there might be different amounts of front and rear parts.
    03871        *
    03872        * Note: The multiheaded parts need to be matched exactly like they are matched on the server, else desyncs will occur.
    03873        *   This is why two matching strategies are needed.
    03874        */
    03875
    03876       bool sequential_matching = IsFrontEngine(v);
    03877
    03878       Vehicle *u = v;
    03879       BEGIN_ENUM_WAGONS(u) {
    03880         if (u->u.rail.other_multiheaded_part != NULL) continue; // we already linked this one
    03881
    03882         if (IsMultiheaded(u)) {
    03883           if (!IsTrainEngine(u)) {
    03884             /* we got a rear car without a front car. We will convert it to a front one */
    03885             SetTrainEngine(u);
    03886             u->spritenum--;
    03887           }
    03888
    03889           /* Find a matching back part */
    03890           EngineID eid = u->engine_type;
    03891           Vehicle *w;
    03892           if (sequential_matching) {
    03893             for (w = GetNextVehicle(u); w != NULL; w = GetNextVehicle(w)) {
    03894               if (w->engine_type != eid || w->u.rail.other_multiheaded_part != NULL || !IsMultiheaded(w)) continue;
    03895
    03896               /* we found a car to partner with this engine. Now we will make sure it face the right way */
    03897               if (IsTrainEngine(w)) {
    03898                 ClearTrainEngine(w);
    03899                 w->spritenum++;
    03900               }
    03901               break;
    03902             }
    03903           } else {
    03904             uint stack_pos = 0;
    03905             for (w = GetNextVehicle(u); w != NULL; w = GetNextVehicle(w)) {
    03906               if (w->engine_type != eid || w->u.rail.other_multiheaded_part != NULL || !IsMultiheaded(w)) continue;
    03907
    03908               if (IsTrainEngine(w)) {
    03909                 stack_pos++;
    03910               } else {
    03911                 if (stack_pos == 0) break;
    03912                 stack_pos--;
    03913               }
    03914             }
    03915           }
    03916
    03917           if (w != NULL) {
    03918             w->u.rail.other_multiheaded_part = u;
    03919             u->u.rail.other_multiheaded_part = w;
    03920           } else {
    03921             /* we got a front car and no rear cars. We will fake this one for forget that it should have been multiheaded */
    03922             ClearMultiheaded(u);
    03923           }
    03924         }
    03925       } END_ENUM_WAGONS(u)
    03926     }
    03927   }
    03928 }
    03929
    03934 void ConvertOldMultiheadToNew()
    03935 {
    03936   Vehicle *v;
    03937   FOR_ALL_VEHICLES(v) {
    03938     if (v->type == VEH_TRAIN) {
    03939       SetBit(v->subtype, 7); // indicates that it's the old format and needs to be converted in the next loop
    03940     }
    03941   }
    03942
    03943   FOR_ALL_VEHICLES(v) {
    03944     if (v->type == VEH_TRAIN) {
    03945       if (HasBit(v->subtype, 7) && ((v->subtype & ~0x80) == 0 || (v->subtype & ~0x80) == 4)) {
    03946         Vehicle *u = v;
    03947
    03948         BEGIN_ENUM_WAGONS(u) {
    03949           const RailVehicleInfo *rvi = RailVehInfo(u->engine_type);
    03950
    03951           ClrBit(u->subtype, 7);
    03952           switch (u->subtype) {
    03953             case 0: /* TS_Front_Engine */
    03954               if (rvi->railveh_type == RAILVEH_MULTIHEAD) SetMultiheaded(u);
    03955               SetFrontEngine(u);
    03956               SetTrainEngine(u);
    03957               break;
    03958
    03959             case 1: /* TS_Artic_Part */
    03960               u->subtype = 0;
    03961               SetArticulatedPart(u);
    03962               break;
    03963
    03964             case 2: /* TS_Not_First */
    03965               u->subtype = 0;
    03966               if (rvi->railveh_type == RAILVEH_WAGON) {
    03967                 // normal wagon
    03968                 SetTrainWagon(u);
    03969                 break;
    03970               }
    03971               if (rvi->railveh_type == RAILVEH_MULTIHEAD && rvi->image_index == u->spritenum - 1) {
    03972                 // rear end of a multiheaded engine
    03973                 SetMultiheaded(u);
    03974                 break;
    03975               }
    03976               if (rvi->railveh_type == RAILVEH_MULTIHEAD) SetMultiheaded(u);
    03977               SetTrainEngine(u);
    03978               break;
    03979
    03980             case 4: /* TS_Free_Car */
    03981               u->subtype = 0;
    03982               SetTrainWagon(u);
    03983               SetFreeWagon(u);
    03984               break;
    03985             default: NOT_REACHED(); break;
    03986           }
    03987         } END_ENUM_WAGONS(u)
    03988       }
    03989     }
    03990   }
    03991 }