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