OpenTTD Source  20241120-master-g6d3adc6169
train_cmd.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
10 #include "stdafx.h"
11 #include "error.h"
12 #include "articulated_vehicles.h"
13 #include "command_func.h"
14 #include "error_func.h"
15 #include "pathfinder/yapf/yapf.hpp"
16 #include "news_func.h"
17 #include "company_func.h"
18 #include "newgrf_sound.h"
19 #include "newgrf_text.h"
20 #include "strings_func.h"
21 #include "viewport_func.h"
22 #include "vehicle_func.h"
23 #include "sound_func.h"
24 #include "ai/ai.hpp"
25 #include "game/game.hpp"
26 #include "newgrf_station.h"
27 #include "effectvehicle_func.h"
28 #include "network/network.h"
29 #include "spritecache.h"
30 #include "core/random_func.hpp"
31 #include "company_base.h"
32 #include "newgrf.h"
33 #include "order_backup.h"
34 #include "zoom_func.h"
35 #include "newgrf_debug.h"
36 #include "framerate_type.h"
37 #include "train_cmd.h"
38 #include "misc_cmd.h"
41 
42 #include "table/strings.h"
43 #include "table/train_sprites.h"
44 
45 #include "safeguards.h"
46 
47 static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck);
48 static bool TrainCheckIfLineEnds(Train *v, bool reverse = true);
49 bool TrainController(Train *v, Vehicle *nomove, bool reverse = true); // Also used in vehicle_sl.cpp.
51 static void CheckIfTrainNeedsService(Train *v);
52 static void CheckNextTrainTile(Train *v);
53 
54 static const uint8_t _vehicle_initial_x_fract[4] = {10, 8, 4, 8};
55 static const uint8_t _vehicle_initial_y_fract[4] = { 8, 4, 8, 10};
56 
57 template <>
58 bool IsValidImageIndex<VEH_TRAIN>(uint8_t image_index)
59 {
60  return image_index < lengthof(_engine_sprite_base);
61 }
62 
63 
69 uint8_t FreightWagonMult(CargoID cargo)
70 {
71  if (!CargoSpec::Get(cargo)->is_freight) return 1;
73 }
74 
77 {
78  bool first = true;
79 
80  for (const Train *v : Train::Iterate()) {
81  if (v->First() == v && !(v->vehstatus & VS_CRASHED)) {
82  for (const Train *u = v, *w = v->Next(); w != nullptr; u = w, w = w->Next()) {
83  if (u->track != TRACK_BIT_DEPOT) {
84  if ((w->track != TRACK_BIT_DEPOT &&
85  std::max(abs(u->x_pos - w->x_pos), abs(u->y_pos - w->y_pos)) != u->CalcNextVehicleOffset()) ||
86  (w->track == TRACK_BIT_DEPOT && TicksToLeaveDepot(u) <= 0)) {
87  SetDParam(0, v->index);
88  SetDParam(1, v->owner);
89  ShowErrorMessage(STR_BROKEN_VEHICLE_LENGTH, INVALID_STRING_ID, WL_CRITICAL);
90 
91  if (!_networking && first) {
92  first = false;
94  }
95  /* Break so we warn only once for each train. */
96  break;
97  }
98  }
99  }
100  }
101  }
102 }
103 
111 {
112  uint16_t max_speed = UINT16_MAX;
113 
114  assert(this->IsFrontEngine() || this->IsFreeWagon());
115 
116  const RailVehicleInfo *rvi_v = RailVehInfo(this->engine_type);
117  EngineID first_engine = this->IsFrontEngine() ? this->engine_type : INVALID_ENGINE;
118  this->gcache.cached_total_length = 0;
119  this->compatible_railtypes = RAILTYPES_NONE;
120 
121  bool train_can_tilt = true;
122  int16_t min_curve_speed_mod = INT16_MAX;
123 
124  for (Train *u = this; u != nullptr; u = u->Next()) {
125  const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type);
126 
127  /* Check the this->first cache. */
128  assert(u->First() == this);
129 
130  /* update the 'first engine' */
131  u->gcache.first_engine = this == u ? INVALID_ENGINE : first_engine;
132  u->railtype = rvi_u->railtype;
133 
134  if (u->IsEngine()) first_engine = u->engine_type;
135 
136  /* Set user defined data to its default value */
137  u->tcache.user_def_data = rvi_u->user_def_data;
138  this->InvalidateNewGRFCache();
139  u->InvalidateNewGRFCache();
140  }
141 
142  for (Train *u = this; u != nullptr; u = u->Next()) {
143  /* Update user defined data (must be done before other properties) */
144  u->tcache.user_def_data = GetVehicleProperty(u, PROP_TRAIN_USER_DATA, u->tcache.user_def_data);
145  this->InvalidateNewGRFCache();
146  u->InvalidateNewGRFCache();
147  }
148 
149  for (Train *u = this; u != nullptr; u = u->Next()) {
150  const Engine *e_u = u->GetEngine();
151  const RailVehicleInfo *rvi_u = &e_u->u.rail;
152 
153  if (!HasBit(e_u->info.misc_flags, EF_RAIL_TILTS)) train_can_tilt = false;
154  min_curve_speed_mod = std::min(min_curve_speed_mod, u->GetCurveSpeedModifier());
155 
156  /* Cache wagon override sprite group. nullptr is returned if there is none */
157  u->tcache.cached_override = GetWagonOverrideSpriteSet(u->engine_type, u->cargo_type, u->gcache.first_engine);
158 
159  /* Reset colour map */
160  u->colourmap = PAL_NONE;
161 
162  /* Update powered-wagon-status and visual effect */
163  u->UpdateVisualEffect(true);
164 
165  if (rvi_v->pow_wag_power != 0 && rvi_u->railveh_type == RAILVEH_WAGON &&
166  UsesWagonOverride(u) && !HasBit(u->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) {
167  /* wagon is powered */
168  SetBit(u->flags, VRF_POWEREDWAGON); // cache 'powered' status
169  } else {
170  ClrBit(u->flags, VRF_POWEREDWAGON);
171  }
172 
173  if (!u->IsArticulatedPart()) {
174  /* Do not count powered wagons for the compatible railtypes, as wagons always
175  have railtype normal */
176  if (rvi_u->power > 0) {
177  this->compatible_railtypes |= GetRailTypeInfo(u->railtype)->powered_railtypes;
178  }
179 
180  /* Some electric engines can be allowed to run on normal rail. It happens to all
181  * existing electric engines when elrails are disabled and then re-enabled */
182  if (HasBit(u->flags, VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL)) {
183  u->railtype = RAILTYPE_RAIL;
184  u->compatible_railtypes |= RAILTYPES_RAIL;
185  }
186 
187  /* max speed is the minimum of the speed limits of all vehicles in the consist */
188  if ((rvi_u->railveh_type != RAILVEH_WAGON || _settings_game.vehicle.wagon_speed_limits) && !UsesWagonOverride(u)) {
189  uint16_t speed = GetVehicleProperty(u, PROP_TRAIN_SPEED, rvi_u->max_speed);
190  if (speed != 0) max_speed = std::min(speed, max_speed);
191  }
192  }
193 
194  uint16_t new_cap = e_u->DetermineCapacity(u);
195  if (allowed_changes & CCF_CAPACITY) {
196  /* Update vehicle capacity. */
197  if (u->cargo_cap > new_cap) u->cargo.Truncate(new_cap);
198  u->refit_cap = std::min(new_cap, u->refit_cap);
199  u->cargo_cap = new_cap;
200  } else {
201  /* Verify capacity hasn't changed. */
202  if (new_cap != u->cargo_cap) ShowNewGrfVehicleError(u->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_CAPACITY, GBUG_VEH_CAPACITY, true);
203  }
204  u->vcache.cached_cargo_age_period = GetVehicleProperty(u, PROP_TRAIN_CARGO_AGE_PERIOD, e_u->info.cargo_age_period);
205 
206  /* check the vehicle length (callback) */
207  uint16_t veh_len = CALLBACK_FAILED;
208  if (e_u->GetGRF() != nullptr && e_u->GetGRF()->grf_version >= 8) {
209  /* Use callback 36 */
210  veh_len = GetVehicleProperty(u, PROP_TRAIN_SHORTEN_FACTOR, CALLBACK_FAILED);
211 
212  if (veh_len != CALLBACK_FAILED && veh_len >= VEHICLE_LENGTH) {
214  }
215  } else if (HasBit(e_u->info.callback_mask, CBM_VEHICLE_LENGTH)) {
216  /* Use callback 11 */
217  veh_len = GetVehicleCallback(CBID_VEHICLE_LENGTH, 0, 0, u->engine_type, u);
218  }
219  if (veh_len == CALLBACK_FAILED) veh_len = rvi_u->shorten_factor;
220  veh_len = VEHICLE_LENGTH - Clamp(veh_len, 0, VEHICLE_LENGTH - 1);
221 
222  if (allowed_changes & CCF_LENGTH) {
223  /* Update vehicle length. */
224  u->gcache.cached_veh_length = veh_len;
225  } else {
226  /* Verify length hasn't changed. */
227  if (veh_len != u->gcache.cached_veh_length) VehicleLengthChanged(u);
228  }
229 
230  this->gcache.cached_total_length += u->gcache.cached_veh_length;
231  this->InvalidateNewGRFCache();
232  u->InvalidateNewGRFCache();
233  }
234 
235  /* store consist weight/max speed in cache */
236  this->vcache.cached_max_speed = max_speed;
237  this->tcache.cached_tilt = train_can_tilt;
238  this->tcache.cached_curve_speed_mod = min_curve_speed_mod;
239  this->tcache.cached_max_curve_speed = this->GetCurveSpeedLimit();
240 
241  /* 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) */
242  this->CargoChanged();
243 
244  if (this->IsFrontEngine()) {
245  this->UpdateAcceleration();
249  InvalidateNewGRFInspectWindow(GSF_TRAINS, this->index);
250  }
251 }
252 
263 int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, int *station_ahead, int *station_length)
264 {
265  const Station *st = Station::Get(station_id);
266  *station_ahead = st->GetPlatformLength(tile, DirToDiagDir(v->direction)) * TILE_SIZE;
267  *station_length = st->GetPlatformLength(tile) * TILE_SIZE;
268 
269  /* Default to the middle of the station for stations stops that are not in
270  * the order list like intermediate stations when non-stop is disabled */
272  if (v->gcache.cached_total_length >= *station_length) {
273  /* The train is longer than the station, make it stop at the far end of the platform */
274  osl = OSL_PLATFORM_FAR_END;
275  } else if (v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetDestination() == station_id) {
276  osl = v->current_order.GetStopLocation();
277  }
278 
279  /* The stop location of the FRONT! of the train */
280  int stop;
281  switch (osl) {
282  default: NOT_REACHED();
283 
285  stop = v->gcache.cached_total_length;
286  break;
287 
288  case OSL_PLATFORM_MIDDLE:
289  stop = *station_length - (*station_length - v->gcache.cached_total_length) / 2;
290  break;
291 
293  stop = *station_length;
294  break;
295  }
296 
297  /* Subtract half the front vehicle length of the train so we get the real
298  * stop location of the train. */
299  return stop - (v->gcache.cached_veh_length + 1) / 2;
300 }
301 
302 
308 {
309  assert(this->First() == this);
310 
311  static const int absolute_max_speed = UINT16_MAX;
312  int max_speed = absolute_max_speed;
313 
314  if (_settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) return max_speed;
315 
316  int curvecount[2] = {0, 0};
317 
318  /* first find the curve speed limit */
319  int numcurve = 0;
320  int sum = 0;
321  int pos = 0;
322  int lastpos = -1;
323  for (const Train *u = this; u->Next() != nullptr; u = u->Next(), pos += u->gcache.cached_veh_length) {
324  Direction this_dir = u->direction;
325  Direction next_dir = u->Next()->direction;
326 
327  DirDiff dirdiff = DirDifference(this_dir, next_dir);
328  if (dirdiff == DIRDIFF_SAME) continue;
329 
330  if (dirdiff == DIRDIFF_45LEFT) curvecount[0]++;
331  if (dirdiff == DIRDIFF_45RIGHT) curvecount[1]++;
332  if (dirdiff == DIRDIFF_45LEFT || dirdiff == DIRDIFF_45RIGHT) {
333  if (lastpos != -1) {
334  numcurve++;
335  sum += pos - lastpos;
336  if (pos - lastpos <= static_cast<int>(VEHICLE_LENGTH) && max_speed > 88) {
337  max_speed = 88;
338  }
339  }
340  lastpos = pos;
341  }
342 
343  /* if we have a 90 degree turn, fix the speed limit to 60 */
344  if (dirdiff == DIRDIFF_90LEFT || dirdiff == DIRDIFF_90RIGHT) {
345  max_speed = 61;
346  }
347  }
348 
349  if (numcurve > 0 && max_speed > 88) {
350  if (curvecount[0] == 1 && curvecount[1] == 1) {
351  max_speed = absolute_max_speed;
352  } else {
353  sum = CeilDiv(sum, VEHICLE_LENGTH);
354  sum /= numcurve;
355  max_speed = 232 - (13 - Clamp(sum, 1, 12)) * (13 - Clamp(sum, 1, 12));
356  }
357  }
358 
359  if (max_speed != absolute_max_speed) {
360  /* Apply the current railtype's curve speed advantage */
361  const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(this->tile));
362  max_speed += (max_speed / 2) * rti->curve_speed;
363 
364  if (this->tcache.cached_tilt) {
365  /* Apply max_speed bonus of 20% for a tilting train */
366  max_speed += max_speed / 5;
367  }
368 
369  /* Apply max_speed modifier (cached value is fixed-point binary with 8 fractional bits)
370  * and clamp the result to an acceptable range. */
371  max_speed += (max_speed * this->tcache.cached_curve_speed_mod) / 256;
372  max_speed = Clamp(max_speed, 2, absolute_max_speed);
373  }
374 
375  return static_cast<uint16_t>(max_speed);
376 }
377 
383 {
384  int max_speed = _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL ?
386  this->tcache.cached_max_curve_speed;
387 
388  if (_settings_game.vehicle.train_acceleration_model == AM_REALISTIC && IsRailStationTile(this->tile)) {
389  StationID sid = GetStationIndex(this->tile);
390  if (this->current_order.ShouldStopAtStation(this, sid)) {
391  int station_ahead;
392  int station_length;
393  int stop_at = GetTrainStopLocation(sid, this->tile, this, &station_ahead, &station_length);
394 
395  /* The distance to go is whatever is still ahead of the train minus the
396  * distance from the train's stop location to the end of the platform */
397  int distance_to_go = station_ahead / TILE_SIZE - (station_length - stop_at) / TILE_SIZE;
398 
399  if (distance_to_go > 0) {
400  int st_max_speed = 120;
401 
402  int delta_v = this->cur_speed / (distance_to_go + 1);
403  if (max_speed > (this->cur_speed - delta_v)) {
404  st_max_speed = this->cur_speed - (delta_v / 10);
405  }
406 
407  st_max_speed = std::max(st_max_speed, 25 * distance_to_go);
408  max_speed = std::min(max_speed, st_max_speed);
409  }
410  }
411  }
412 
413  for (const Train *u = this; u != nullptr; u = u->Next()) {
414  if (_settings_game.vehicle.train_acceleration_model == AM_REALISTIC && u->track == TRACK_BIT_DEPOT) {
415  max_speed = std::min(max_speed, 61);
416  break;
417  }
418 
419  /* Vehicle is on the middle part of a bridge. */
420  if (u->track == TRACK_BIT_WORMHOLE && !(u->vehstatus & VS_HIDDEN)) {
421  max_speed = std::min<int>(max_speed, GetBridgeSpec(GetBridgeType(u->tile))->speed);
422  }
423  }
424 
425  max_speed = std::min<int>(max_speed, this->current_order.GetMaxSpeed());
426  return std::min<int>(max_speed, this->gcache.cached_max_track_speed);
427 }
428 
431 {
432  assert(this->IsFrontEngine() || this->IsFreeWagon());
433 
434  uint power = this->gcache.cached_power;
435  uint weight = this->gcache.cached_weight;
436  assert(weight != 0);
437  this->acceleration = Clamp(power / weight * 4, 1, 255);
438 }
439 
440 int Train::GetCursorImageOffset() const
441 {
442  if (this->gcache.cached_veh_length != 8 && HasBit(this->flags, VRF_REVERSE_DIRECTION) && !HasBit(EngInfo(this->engine_type)->misc_flags, EF_RAIL_FLIPS)) {
443  int reference_width = TRAININFO_DEFAULT_VEHICLE_WIDTH;
444 
445  const Engine *e = this->GetEngine();
446  if (e->GetGRF() != nullptr && is_custom_sprite(e->u.rail.image_index)) {
447  reference_width = e->GetGRF()->traininfo_vehicle_width;
448  }
449 
450  return ScaleSpriteTrad((this->gcache.cached_veh_length - (int)VEHICLE_LENGTH) * reference_width / (int)VEHICLE_LENGTH);
451  }
452  return 0;
453 }
454 
461 {
462  int reference_width = TRAININFO_DEFAULT_VEHICLE_WIDTH;
463  int vehicle_pitch = 0;
464 
465  const Engine *e = this->GetEngine();
466  if (e->GetGRF() != nullptr && is_custom_sprite(e->u.rail.image_index)) {
467  reference_width = e->GetGRF()->traininfo_vehicle_width;
468  vehicle_pitch = e->GetGRF()->traininfo_vehicle_pitch;
469  }
470 
471  if (offset != nullptr) {
472  if (HasBit(this->flags, VRF_REVERSE_DIRECTION) && !HasBit(EngInfo(this->engine_type)->misc_flags, EF_RAIL_FLIPS)) {
473  offset->x = ScaleSpriteTrad(((int)this->gcache.cached_veh_length - (int)VEHICLE_LENGTH / 2) * reference_width / (int)VEHICLE_LENGTH);
474  } else {
475  offset->x = ScaleSpriteTrad(reference_width) / 2;
476  }
477  offset->y = ScaleSpriteTrad(vehicle_pitch);
478  }
479  return ScaleSpriteTrad(this->gcache.cached_veh_length * reference_width / VEHICLE_LENGTH);
480 }
481 
482 static SpriteID GetDefaultTrainSprite(uint8_t spritenum, Direction direction)
483 {
484  assert(IsValidImageIndex<VEH_TRAIN>(spritenum));
485  return ((direction + _engine_sprite_add[spritenum]) & _engine_sprite_and[spritenum]) + _engine_sprite_base[spritenum];
486 }
487 
494 void Train::GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const
495 {
496  uint8_t spritenum = this->spritenum;
497 
499 
500  if (is_custom_sprite(spritenum)) {
501  GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)), image_type, result);
502  if (result->IsValid()) return;
503 
505  }
506 
507  assert(IsValidImageIndex<VEH_TRAIN>(spritenum));
508  SpriteID sprite = GetDefaultTrainSprite(spritenum, direction);
509 
510  if (this->cargo.StoredCount() >= this->cargo_cap / 2U) sprite += _wagon_full_adder[spritenum];
511 
512  result->Set(sprite);
513 }
514 
515 static void GetRailIcon(EngineID engine, bool rear_head, int &y, EngineImageType image_type, VehicleSpriteSeq *result)
516 {
517  const Engine *e = Engine::Get(engine);
518  Direction dir = rear_head ? DIR_E : DIR_W;
519  uint8_t spritenum = e->u.rail.image_index;
520 
521  if (is_custom_sprite(spritenum)) {
522  GetCustomVehicleIcon(engine, dir, image_type, result);
523  if (result->IsValid()) {
524  if (e->GetGRF() != nullptr) {
526  }
527  return;
528  }
529 
530  spritenum = Engine::Get(engine)->original_image_index;
531  }
532 
533  if (rear_head) spritenum++;
534 
535  result->Set(GetDefaultTrainSprite(spritenum, DIR_W));
536 }
537 
538 void DrawTrainEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type)
539 {
540  if (RailVehInfo(engine)->railveh_type == RAILVEH_MULTIHEAD) {
541  int yf = y;
542  int yr = y;
543 
544  VehicleSpriteSeq seqf, seqr;
545  GetRailIcon(engine, false, yf, image_type, &seqf);
546  GetRailIcon(engine, true, yr, image_type, &seqr);
547 
548  Rect rectf, rectr;
549  seqf.GetBounds(&rectf);
550  seqr.GetBounds(&rectr);
551 
552  preferred_x = Clamp(preferred_x,
553  left - UnScaleGUI(rectf.left) + ScaleSpriteTrad(14),
554  right - UnScaleGUI(rectr.right) - ScaleSpriteTrad(15));
555 
556  seqf.Draw(preferred_x - ScaleSpriteTrad(14), yf, pal, pal == PALETTE_CRASH);
557  seqr.Draw(preferred_x + ScaleSpriteTrad(15), yr, pal, pal == PALETTE_CRASH);
558  } else {
559  VehicleSpriteSeq seq;
560  GetRailIcon(engine, false, y, image_type, &seq);
561 
562  Rect rect;
563  seq.GetBounds(&rect);
564  preferred_x = Clamp(preferred_x,
565  left - UnScaleGUI(rect.left),
566  right - UnScaleGUI(rect.right));
567 
568  seq.Draw(preferred_x, y, pal, pal == PALETTE_CRASH);
569  }
570 }
571 
581 void GetTrainSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type)
582 {
583  int y = 0;
584 
585  VehicleSpriteSeq seq;
586  GetRailIcon(engine, false, y, image_type, &seq);
587 
588  Rect rect;
589  seq.GetBounds(&rect);
590 
591  width = UnScaleGUI(rect.Width());
592  height = UnScaleGUI(rect.Height());
593  xoffs = UnScaleGUI(rect.left);
594  yoffs = UnScaleGUI(rect.top);
595 
596  if (RailVehInfo(engine)->railveh_type == RAILVEH_MULTIHEAD) {
597  GetRailIcon(engine, true, y, image_type, &seq);
598  seq.GetBounds(&rect);
599 
600  /* Calculate values relative to an imaginary center between the two sprites. */
601  width = ScaleSpriteTrad(TRAININFO_DEFAULT_VEHICLE_WIDTH) + UnScaleGUI(rect.right) - xoffs;
602  height = std::max<uint>(height, UnScaleGUI(rect.Height()));
603  xoffs = xoffs - ScaleSpriteTrad(TRAININFO_DEFAULT_VEHICLE_WIDTH) / 2;
604  yoffs = std::min(yoffs, UnScaleGUI(rect.top));
605  }
606 }
607 
617 {
618  const RailVehicleInfo *rvi = &e->u.rail;
619 
620  /* Check that the wagon can drive on the track in question */
621  if (!IsCompatibleRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR;
622 
623  if (flags & DC_EXEC) {
624  Train *v = new Train();
625  *ret = v;
626  v->spritenum = rvi->image_index;
627 
628  v->engine_type = e->index;
629  v->gcache.first_engine = INVALID_ENGINE; // needs to be set before first callback
630 
632 
633  v->direction = DiagDirToDir(dir);
634  v->tile = tile;
635 
636  int x = TileX(tile) * TILE_SIZE | _vehicle_initial_x_fract[dir];
637  int y = TileY(tile) * TILE_SIZE | _vehicle_initial_y_fract[dir];
638 
639  v->x_pos = x;
640  v->y_pos = y;
641  v->z_pos = GetSlopePixelZ(x, y, true);
642  v->owner = _current_company;
643  v->track = TRACK_BIT_DEPOT;
645 
646  v->SetWagon();
647 
648  v->SetFreeWagon();
650 
652  assert(IsValidCargoID(v->cargo_type));
653  v->cargo_cap = rvi->capacity;
654  v->refit_cap = 0;
655 
656  v->railtype = rvi->railtype;
657 
661  v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
662  v->random_bits = Random();
663 
664  v->group_id = DEFAULT_GROUP;
665 
666  if (TestVehicleBuildProbability(v, v->engine_type, BuildProbabilityType::Reversed)) SetBit(v->flags, VRF_REVERSE_DIRECTION);
668 
669  v->UpdatePosition();
670  v->First()->ConsistChanged(CCF_ARRANGE);
672 
674 
675  /* Try to connect the vehicle to one of free chains of wagons. */
676  for (Train *w : Train::Iterate()) {
677  if (w->tile == tile &&
678  w->IsFreeWagon() &&
679  w->engine_type == e->index &&
680  w->First() != v &&
681  !(w->vehstatus & VS_CRASHED)) {
682  if (Command<CMD_MOVE_RAIL_VEHICLE>::Do(DC_EXEC, v->index, w->Last()->index, true).Succeeded()) {
683  break;
684  }
685  }
686  }
687  }
688 
689  return CommandCost();
690 }
691 
694 {
695  assert(u->IsEngine());
696  for (const Train *v : Train::Iterate()) {
697  if (v->IsFreeWagon() && v->tile == u->tile &&
698  v->track == TRACK_BIT_DEPOT) {
699  if (Command<CMD_MOVE_RAIL_VEHICLE>::Do(DC_EXEC, v->index, u->index, true).Failed()) {
700  break;
701  }
702  }
703  }
704 }
705 
706 static void AddRearEngineToMultiheadedTrain(Train *v)
707 {
708  Train *u = new Train();
709  v->value >>= 1;
710  u->value = v->value;
711  u->direction = v->direction;
712  u->owner = v->owner;
713  u->tile = v->tile;
714  u->x_pos = v->x_pos;
715  u->y_pos = v->y_pos;
716  u->z_pos = v->z_pos;
717  u->track = TRACK_BIT_DEPOT;
718  u->vehstatus = v->vehstatus & ~VS_STOPPED;
719  u->spritenum = v->spritenum + 1;
720  u->cargo_type = v->cargo_type;
722  u->cargo_cap = v->cargo_cap;
723  u->refit_cap = v->refit_cap;
724  u->railtype = v->railtype;
725  u->engine_type = v->engine_type;
728  u->build_year = v->build_year;
729  u->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
730  u->random_bits = Random();
731  v->SetMultiheaded();
732  u->SetMultiheaded();
733  v->SetNext(u);
734  if (TestVehicleBuildProbability(u, u->engine_type, BuildProbabilityType::Reversed)) SetBit(u->flags, VRF_REVERSE_DIRECTION);
735  u->UpdatePosition();
736 
737  /* Now we need to link the front and rear engines together */
738  v->other_multiheaded_part = u;
739  u->other_multiheaded_part = v;
740 }
741 
751 {
752  const RailVehicleInfo *rvi = &e->u.rail;
753 
754  if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildRailWagon(flags, tile, e, ret);
755 
756  /* Check if depot and new engine uses the same kind of tracks *
757  * We need to see if the engine got power on the tile to avoid electric engines in non-electric depots */
758  if (!HasPowerOnRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR;
759 
760  if (flags & DC_EXEC) {
762  int x = TileX(tile) * TILE_SIZE + _vehicle_initial_x_fract[dir];
763  int y = TileY(tile) * TILE_SIZE + _vehicle_initial_y_fract[dir];
764 
765  Train *v = new Train();
766  *ret = v;
767  v->direction = DiagDirToDir(dir);
768  v->tile = tile;
769  v->owner = _current_company;
770  v->x_pos = x;
771  v->y_pos = y;
772  v->z_pos = GetSlopePixelZ(x, y, true);
773  v->track = TRACK_BIT_DEPOT;
775  v->spritenum = rvi->image_index;
777  assert(IsValidCargoID(v->cargo_type));
778  v->cargo_cap = rvi->capacity;
779  v->refit_cap = 0;
780  v->last_station_visited = INVALID_STATION;
781  v->last_loading_station = INVALID_STATION;
782 
783  v->engine_type = e->index;
784  v->gcache.first_engine = INVALID_ENGINE; // needs to be set before first callback
785 
786  v->reliability = e->reliability;
788  v->max_age = e->GetLifeLengthInDays();
789 
790  v->railtype = rvi->railtype;
791 
792  v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_trains);
796  v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
797  v->random_bits = Random();
798 
800  v->SetServiceIntervalIsPercent(Company::Get(_current_company)->settings.vehicle.servint_ispercent);
801 
802  v->group_id = DEFAULT_GROUP;
803 
804  v->SetFrontEngine();
805  v->SetEngine();
806 
807  if (TestVehicleBuildProbability(v, v->engine_type, BuildProbabilityType::Reversed)) SetBit(v->flags, VRF_REVERSE_DIRECTION);
808  v->UpdatePosition();
809 
810  if (rvi->railveh_type == RAILVEH_MULTIHEAD) {
811  AddRearEngineToMultiheadedTrain(v);
812  } else {
814  }
815 
818 
820  }
821 
822  return CommandCost();
823 }
824 
825 static Train *FindGoodVehiclePos(const Train *src)
826 {
827  EngineID eng = src->engine_type;
828  TileIndex tile = src->tile;
829 
830  for (Train *dst : Train::Iterate()) {
831  if (dst->IsFreeWagon() && dst->tile == tile && !(dst->vehstatus & VS_CRASHED)) {
832  /* check so all vehicles in the line have the same engine. */
833  Train *t = dst;
834  while (t->engine_type == eng) {
835  t = t->Next();
836  if (t == nullptr) return dst;
837  }
838  }
839  }
840 
841  return nullptr;
842 }
843 
845 typedef std::vector<Train *> TrainList;
846 
852 static void MakeTrainBackup(TrainList &list, Train *t)
853 {
854  for (; t != nullptr; t = t->Next()) list.push_back(t);
855 }
856 
861 static void RestoreTrainBackup(TrainList &list)
862 {
863  /* No train, nothing to do. */
864  if (list.empty()) return;
865 
866  Train *prev = nullptr;
867  /* Iterate over the list and rebuild it. */
868  for (Train *t : list) {
869  if (prev != nullptr) {
870  prev->SetNext(t);
871  } else if (t->Previous() != nullptr) {
872  /* Make sure the head of the train is always the first in the chain. */
873  t->Previous()->SetNext(nullptr);
874  }
875  prev = t;
876  }
877 }
878 
884 static void RemoveFromConsist(Train *part, bool chain = false)
885 {
886  Train *tail = chain ? part->Last() : part->GetLastEnginePart();
887 
888  /* Unlink at the front, but make it point to the next
889  * vehicle after the to be remove part. */
890  if (part->Previous() != nullptr) part->Previous()->SetNext(tail->Next());
891 
892  /* Unlink at the back */
893  tail->SetNext(nullptr);
894 }
895 
901 static void InsertInConsist(Train *dst, Train *chain)
902 {
903  /* We do not want to add something in the middle of an articulated part. */
904  assert(dst != nullptr && (dst->Next() == nullptr || !dst->Next()->IsArticulatedPart()));
905 
906  chain->Last()->SetNext(dst->Next());
907  dst->SetNext(chain);
908 }
909 
915 static void NormaliseDualHeads(Train *t)
916 {
917  for (; t != nullptr; t = t->GetNextVehicle()) {
918  if (!t->IsMultiheaded() || !t->IsEngine()) continue;
919 
920  /* Make sure that there are no free cars before next engine */
921  Train *u;
922  for (u = t; u->Next() != nullptr && !u->Next()->IsEngine(); u = u->Next()) {}
923 
924  if (u == t->other_multiheaded_part) continue;
925 
926  /* Remove the part from the 'wrong' train */
927  RemoveFromConsist(t->other_multiheaded_part);
928  /* And add it to the 'right' train */
929  InsertInConsist(u, t->other_multiheaded_part);
930  }
931 }
932 
937 static void NormaliseSubtypes(Train *chain)
938 {
939  /* Nothing to do */
940  if (chain == nullptr) return;
941 
942  /* We must be the first in the chain. */
943  assert(chain->Previous() == nullptr);
944 
945  /* Set the appropriate bits for the first in the chain. */
946  if (chain->IsWagon()) {
947  chain->SetFreeWagon();
948  } else {
949  assert(chain->IsEngine());
950  chain->SetFrontEngine();
951  }
952 
953  /* Now clear the bits for the rest of the chain */
954  for (Train *t = chain->Next(); t != nullptr; t = t->Next()) {
955  t->ClearFreeWagon();
956  t->ClearFrontEngine();
957  }
958 }
959 
969 static CommandCost CheckNewTrain(Train *original_dst, Train *dst, Train *original_src, Train *src)
970 {
971  /* Just add 'new' engines and subtract the original ones.
972  * If that's less than or equal to 0 we can be sure we did
973  * not add any engines (read: trains) along the way. */
974  if ((src != nullptr && src->IsEngine() ? 1 : 0) +
975  (dst != nullptr && dst->IsEngine() ? 1 : 0) -
976  (original_src != nullptr && original_src->IsEngine() ? 1 : 0) -
977  (original_dst != nullptr && original_dst->IsEngine() ? 1 : 0) <= 0) {
978  return CommandCost();
979  }
980 
981  /* Get a free unit number and check whether it's within the bounds.
982  * There will always be a maximum of one new train. */
984 
985  return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME);
986 }
987 
994 {
995  /* No multi-part train, no need to check. */
996  if (t == nullptr || t->Next() == nullptr) return CommandCost();
997 
998  /* The maximum length for a train. For each part we decrease this by one
999  * and if the result is negative the train is simply too long. */
1001 
1002  /* For free-wagon chains, check if they are within the max_train_length limit. */
1003  if (!t->IsEngine()) {
1004  t = t->Next();
1005  while (t != nullptr) {
1006  allowed_len -= t->gcache.cached_veh_length;
1007 
1008  t = t->Next();
1009  }
1010 
1011  if (allowed_len < 0) return_cmd_error(STR_ERROR_TRAIN_TOO_LONG);
1012  return CommandCost();
1013  }
1014 
1015  Train *head = t;
1016  Train *prev = t;
1017 
1018  /* Break the prev -> t link so it always holds within the loop. */
1019  t = t->Next();
1020  prev->SetNext(nullptr);
1021 
1022  /* Make sure the cache is cleared. */
1023  head->InvalidateNewGRFCache();
1024 
1025  while (t != nullptr) {
1026  allowed_len -= t->gcache.cached_veh_length;
1027 
1028  Train *next = t->Next();
1029 
1030  /* Unlink the to-be-added piece; it is already unlinked from the previous
1031  * part due to the fact that the prev -> t link is broken. */
1032  t->SetNext(nullptr);
1033 
1034  /* Don't check callback for articulated or rear dual headed parts */
1035  if (!t->IsArticulatedPart() && !t->IsRearDualheaded()) {
1036  /* Back up and clear the first_engine data to avoid using wagon override group */
1037  EngineID first_engine = t->gcache.first_engine;
1039 
1040  /* We don't want the cache to interfere. head's cache is cleared before
1041  * the loop and after each callback does not need to be cleared here. */
1042  t->InvalidateNewGRFCache();
1043 
1044  uint16_t callback = GetVehicleCallbackParent(CBID_TRAIN_ALLOW_WAGON_ATTACH, 0, 0, head->engine_type, t, head);
1045 
1046  /* Restore original first_engine data */
1047  t->gcache.first_engine = first_engine;
1048 
1049  /* We do not want to remember any cached variables from the test run */
1050  t->InvalidateNewGRFCache();
1051  head->InvalidateNewGRFCache();
1052 
1053  if (callback != CALLBACK_FAILED) {
1054  /* A failing callback means everything is okay */
1055  StringID error = STR_NULL;
1056 
1057  if (head->GetGRF()->grf_version < 8) {
1058  if (callback == 0xFD) error = STR_ERROR_INCOMPATIBLE_RAIL_TYPES;
1059  if (callback < 0xFD) error = GetGRFStringID(head->GetGRFID(), 0xD000 + callback);
1060  if (callback >= 0x100) ErrorUnknownCallbackResult(head->GetGRFID(), CBID_TRAIN_ALLOW_WAGON_ATTACH, callback);
1061  } else {
1062  if (callback < 0x400) {
1063  error = GetGRFStringID(head->GetGRFID(), 0xD000 + callback);
1064  } else {
1065  switch (callback) {
1066  case 0x400: // allow if railtypes match (always the case for OpenTTD)
1067  case 0x401: // allow
1068  break;
1069 
1070  default: // unknown reason -> disallow
1071  case 0x402: // disallow attaching
1072  error = STR_ERROR_INCOMPATIBLE_RAIL_TYPES;
1073  break;
1074  }
1075  }
1076  }
1077 
1078  if (error != STR_NULL) return_cmd_error(error);
1079  }
1080  }
1081 
1082  /* And link it to the new part. */
1083  prev->SetNext(t);
1084  prev = t;
1085  t = next;
1086  }
1087 
1088  if (allowed_len < 0) return_cmd_error(STR_ERROR_TRAIN_TOO_LONG);
1089  return CommandCost();
1090 }
1091 
1102 static CommandCost ValidateTrains(Train *original_dst, Train *dst, Train *original_src, Train *src, bool check_limit)
1103 {
1104  /* Check whether we may actually construct the trains. */
1105  CommandCost ret = CheckTrainAttachment(src);
1106  if (ret.Failed()) return ret;
1107  ret = CheckTrainAttachment(dst);
1108  if (ret.Failed()) return ret;
1109 
1110  /* Check whether we need to build a new train. */
1111  return check_limit ? CheckNewTrain(original_dst, dst, original_src, src) : CommandCost();
1112 }
1113 
1122 static void ArrangeTrains(Train **dst_head, Train *dst, Train **src_head, Train *src, bool move_chain)
1123 {
1124  /* First determine the front of the two resulting trains */
1125  if (*src_head == *dst_head) {
1126  /* If we aren't moving part(s) to a new train, we are just moving the
1127  * front back and there is not destination head. */
1128  *dst_head = nullptr;
1129  } else if (*dst_head == nullptr) {
1130  /* If we are moving to a new train the head of the move train would become
1131  * the head of the new vehicle. */
1132  *dst_head = src;
1133  }
1134 
1135  if (src == *src_head) {
1136  /* If we are moving the front of a train then we are, in effect, creating
1137  * a new head for the train. Point to that. Unless we are moving the whole
1138  * train in which case there is not 'source' train anymore.
1139  * In case we are a multiheaded part we want the complete thing to come
1140  * with us, so src->GetNextUnit(), however... when we are e.g. a wagon
1141  * that is followed by a rear multihead we do not want to include that. */
1142  *src_head = move_chain ? nullptr :
1143  (src->IsMultiheaded() ? src->GetNextUnit() : src->GetNextVehicle());
1144  }
1145 
1146  /* Now it's just simply removing the part that we are going to move from the
1147  * source train and *if* the destination is a not a new train add the chain
1148  * at the destination location. */
1149  RemoveFromConsist(src, move_chain);
1150  if (*dst_head != src) InsertInConsist(dst, src);
1151 
1152  /* Now normalise the dual heads, that is move the dual heads around in such
1153  * a way that the head and rear of a dual head are in the same train */
1154  NormaliseDualHeads(*src_head);
1155  NormaliseDualHeads(*dst_head);
1156 }
1157 
1163 static void NormaliseTrainHead(Train *head)
1164 {
1165  /* Not much to do! */
1166  if (head == nullptr) return;
1167 
1168  /* Tell the 'world' the train changed. */
1169  head->ConsistChanged(CCF_ARRANGE);
1170  UpdateTrainGroupID(head);
1171 
1172  /* Not a front engine, i.e. a free wagon chain. No need to do more. */
1173  if (!head->IsFrontEngine()) return;
1174 
1175  /* Update the refit button and window */
1178 
1179  /* If we don't have a unit number yet, set one. */
1180  if (head->unitnumber != 0) return;
1181  head->unitnumber = Company::Get(head->owner)->freeunits[head->type].UseID(GetFreeUnitNumber(VEH_TRAIN));
1182 }
1183 
1193 CommandCost CmdMoveRailVehicle(DoCommandFlag flags, VehicleID src_veh, VehicleID dest_veh, bool move_chain)
1194 {
1195  Train *src = Train::GetIfValid(src_veh);
1196  if (src == nullptr) return CMD_ERROR;
1197 
1198  CommandCost ret = CheckOwnership(src->owner);
1199  if (ret.Failed()) return ret;
1200 
1201  /* Do not allow moving crashed vehicles inside the depot, it is likely to cause asserts later */
1202  if (src->vehstatus & VS_CRASHED) return CMD_ERROR;
1203 
1204  /* if nothing is selected as destination, try and find a matching vehicle to drag to. */
1205  Train *dst;
1206  if (dest_veh == INVALID_VEHICLE) {
1207  dst = (src->IsEngine() || (flags & DC_AUTOREPLACE)) ? nullptr : FindGoodVehiclePos(src);
1208  } else {
1209  dst = Train::GetIfValid(dest_veh);
1210  if (dst == nullptr) return CMD_ERROR;
1211 
1212  ret = CheckOwnership(dst->owner);
1213  if (ret.Failed()) return ret;
1214 
1215  /* Do not allow appending to crashed vehicles, too */
1216  if (dst->vehstatus & VS_CRASHED) return CMD_ERROR;
1217  }
1218 
1219  /* if an articulated part is being handled, deal with its parent vehicle */
1220  src = src->GetFirstEnginePart();
1221  if (dst != nullptr) {
1222  dst = dst->GetFirstEnginePart();
1223  }
1224 
1225  /* don't move the same vehicle.. */
1226  if (src == dst) return CommandCost();
1227 
1228  /* locate the head of the two chains */
1229  Train *src_head = src->First();
1230  Train *dst_head;
1231  if (dst != nullptr) {
1232  dst_head = dst->First();
1233  if (dst_head->tile != src_head->tile) return CMD_ERROR;
1234  /* Now deal with articulated part of destination wagon */
1235  dst = dst->GetLastEnginePart();
1236  } else {
1237  dst_head = nullptr;
1238  }
1239 
1240  if (src->IsRearDualheaded()) return_cmd_error(STR_ERROR_REAR_ENGINE_FOLLOW_FRONT);
1241 
1242  /* When moving all wagons, we can't have the same src_head and dst_head */
1243  if (move_chain && src_head == dst_head) return CommandCost();
1244 
1245  /* When moving a multiheaded part to be place after itself, bail out. */
1246  if (!move_chain && dst != nullptr && dst->IsRearDualheaded() && src == dst->other_multiheaded_part) return CommandCost();
1247 
1248  /* Check if all vehicles in the source train are stopped inside a depot. */
1249  if (!src_head->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT);
1250 
1251  /* Check if all vehicles in the destination train are stopped inside a depot. */
1252  if (dst_head != nullptr && !dst_head->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT);
1253 
1254  /* First make a backup of the order of the trains. That way we can do
1255  * whatever we want with the order and later on easily revert. */
1256  TrainList original_src;
1257  TrainList original_dst;
1258 
1259  MakeTrainBackup(original_src, src_head);
1260  MakeTrainBackup(original_dst, dst_head);
1261 
1262  /* Also make backup of the original heads as ArrangeTrains can change them.
1263  * For the destination head we do not care if it is the same as the source
1264  * head because in that case it's just a copy. */
1265  Train *original_src_head = src_head;
1266  Train *original_dst_head = (dst_head == src_head ? nullptr : dst_head);
1267 
1268  /* We want this information from before the rearrangement, but execute this after the validation.
1269  * original_src_head can't be nullptr; src is by definition != nullptr, so src_head can't be nullptr as
1270  * src->GetFirst() always yields non-nullptr, so eventually original_src_head != nullptr as well. */
1271  bool original_src_head_front_engine = original_src_head->IsFrontEngine();
1272  bool original_dst_head_front_engine = original_dst_head != nullptr && original_dst_head->IsFrontEngine();
1273 
1274  /* (Re)arrange the trains in the wanted arrangement. */
1275  ArrangeTrains(&dst_head, dst, &src_head, src, move_chain);
1276 
1277  if ((flags & DC_AUTOREPLACE) == 0) {
1278  /* If the autoreplace flag is set we do not need to test for the validity
1279  * because we are going to revert the train to its original state. As we
1280  * assume the original state was correct autoreplace can skip this. */
1281  ret = ValidateTrains(original_dst_head, dst_head, original_src_head, src_head, true);
1282  if (ret.Failed()) {
1283  /* Restore the train we had. */
1284  RestoreTrainBackup(original_src);
1285  RestoreTrainBackup(original_dst);
1286  return ret;
1287  }
1288  }
1289 
1290  /* do it? */
1291  if (flags & DC_EXEC) {
1292  /* Remove old heads from the statistics */
1293  if (original_src_head_front_engine) GroupStatistics::CountVehicle(original_src_head, -1);
1294  if (original_dst_head_front_engine) GroupStatistics::CountVehicle(original_dst_head, -1);
1295 
1296  /* First normalise the sub types of the chains. */
1297  NormaliseSubtypes(src_head);
1298  NormaliseSubtypes(dst_head);
1299 
1300  /* There are 14 different cases:
1301  * 1) front engine gets moved to a new train, it stays a front engine.
1302  * a) the 'next' part is a wagon that becomes a free wagon chain.
1303  * b) the 'next' part is an engine that becomes a front engine.
1304  * c) there is no 'next' part, nothing else happens
1305  * 2) front engine gets moved to another train, it is not a front engine anymore
1306  * a) the 'next' part is a wagon that becomes a free wagon chain.
1307  * b) the 'next' part is an engine that becomes a front engine.
1308  * c) there is no 'next' part, nothing else happens
1309  * 3) front engine gets moved to later in the current train, it is not a front engine anymore.
1310  * a) the 'next' part is a wagon that becomes a free wagon chain.
1311  * b) the 'next' part is an engine that becomes a front engine.
1312  * 4) free wagon gets moved
1313  * a) the 'next' part is a wagon that becomes a free wagon chain.
1314  * b) the 'next' part is an engine that becomes a front engine.
1315  * c) there is no 'next' part, nothing else happens
1316  * 5) non front engine gets moved and becomes a new train, nothing else happens
1317  * 6) non front engine gets moved within a train / to another train, nothing happens
1318  * 7) wagon gets moved, nothing happens
1319  */
1320  if (src == original_src_head && src->IsEngine() && !src->IsFrontEngine()) {
1321  /* Cases #2 and #3: the front engine gets trashed. */
1327  DeleteNewGRFInspectWindow(GSF_TRAINS, src->index);
1329 
1330  if (src_head != nullptr && src_head->IsFrontEngine()) {
1331  /* Cases #?b: Transfer order, unit number and other stuff
1332  * to the new front engine. */
1333  src_head->orders = src->orders;
1334  if (src_head->orders != nullptr) src_head->AddToShared(src);
1335  src_head->CopyVehicleConfigAndStatistics(src);
1336  }
1337  /* Remove stuff not valid anymore for non-front engines. */
1338  DeleteVehicleOrders(src);
1339  src->ReleaseUnitNumber();
1340  src->name.clear();
1341  }
1342 
1343  /* We weren't a front engine but are becoming one. So
1344  * we should be put in the default group. */
1345  if (original_src_head != src && dst_head == src) {
1348  }
1349 
1350  /* Handle 'new engine' part of cases #1b, #2b, #3b, #4b and #5 in NormaliseTrainHead. */
1351  NormaliseTrainHead(src_head);
1352  NormaliseTrainHead(dst_head);
1353 
1354  /* Add new heads to statistics.
1355  * This should be done after NormaliseTrainHead due to engine total limit checks in GetFreeUnitNumber. */
1356  if (src_head != nullptr && src_head->IsFrontEngine()) GroupStatistics::CountVehicle(src_head, 1);
1357  if (dst_head != nullptr && dst_head->IsFrontEngine()) GroupStatistics::CountVehicle(dst_head, 1);
1358 
1359  if ((flags & DC_NO_CARGO_CAP_CHECK) == 0) {
1360  CheckCargoCapacity(src_head);
1361  CheckCargoCapacity(dst_head);
1362  }
1363 
1364  if (src_head != nullptr) src_head->First()->MarkDirty();
1365  if (dst_head != nullptr) dst_head->First()->MarkDirty();
1366 
1367  /* We are undoubtedly changing something in the depot and train list. */
1370  } else {
1371  /* We don't want to execute what we're just tried. */
1372  RestoreTrainBackup(original_src);
1373  RestoreTrainBackup(original_dst);
1374  }
1375 
1376  return CommandCost();
1377 }
1378 
1391 CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, bool sell_chain, bool backup_order, ClientID user)
1392 {
1393  Train *v = Train::From(t)->GetFirstEnginePart();
1394  Train *first = v->First();
1395 
1396  if (v->IsRearDualheaded()) return_cmd_error(STR_ERROR_REAR_ENGINE_FOLLOW_FRONT);
1397 
1398  /* First make a backup of the order of the train. That way we can do
1399  * whatever we want with the order and later on easily revert. */
1400  TrainList original;
1401  MakeTrainBackup(original, first);
1402 
1403  /* We need to keep track of the new head and the head of what we're going to sell. */
1404  Train *new_head = first;
1405  Train *sell_head = nullptr;
1406 
1407  /* Split the train in the wanted way. */
1408  ArrangeTrains(&sell_head, nullptr, &new_head, v, sell_chain);
1409 
1410  /* We don't need to validate the second train; it's going to be sold. */
1411  CommandCost ret = ValidateTrains(nullptr, nullptr, first, new_head, (flags & DC_AUTOREPLACE) == 0);
1412  if (ret.Failed()) {
1413  /* Restore the train we had. */
1414  RestoreTrainBackup(original);
1415  return ret;
1416  }
1417 
1418  if (first->orders == nullptr && !OrderList::CanAllocateItem()) {
1419  /* Restore the train we had. */
1420  RestoreTrainBackup(original);
1421  return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS);
1422  }
1423 
1425  for (Train *part = sell_head; part != nullptr; part = part->Next()) cost.AddCost(-part->value);
1426 
1427  /* do it? */
1428  if (flags & DC_EXEC) {
1429  /* First normalise the sub types of the chain. */
1430  NormaliseSubtypes(new_head);
1431 
1432  if (v == first && !sell_chain && new_head != nullptr && new_head->IsFrontEngine()) {
1433  if (v->IsEngine()) {
1434  /* We are selling the front engine. In this case we want to
1435  * 'give' the order, unit number and such to the new head. */
1436  new_head->orders = first->orders;
1437  new_head->AddToShared(first);
1438  DeleteVehicleOrders(first);
1439 
1440  /* Copy other important data from the front engine */
1441  new_head->CopyVehicleConfigAndStatistics(first);
1442  }
1443  GroupStatistics::CountVehicle(new_head, 1); // after copying over the profit, if required
1444  } else if (v->IsPrimaryVehicle() && backup_order) {
1445  OrderBackup::Backup(v, user);
1446  }
1447 
1448  /* We need to update the information about the train. */
1449  NormaliseTrainHead(new_head);
1450 
1451  /* We are undoubtedly changing something in the depot and train list. */
1454 
1455  /* Actually delete the sold 'goods' */
1456  delete sell_head;
1457  } else {
1458  /* We don't want to execute what we're just tried. */
1459  RestoreTrainBackup(original);
1460  }
1461 
1462  return cost;
1463 }
1464 
1466 {
1467  /* Set common defaults. */
1468  this->x_offs = -1;
1469  this->y_offs = -1;
1470  this->x_extent = 3;
1471  this->y_extent = 3;
1472  this->z_extent = 6;
1473  this->x_bb_offs = 0;
1474  this->y_bb_offs = 0;
1475 
1476  /* Set if flipped and engine is NOT flagged with custom flip handling. */
1477  int flipped = HasBit(this->flags, VRF_REVERSE_DIRECTION) && !HasBit(EngInfo(this->engine_type)->misc_flags, EF_RAIL_FLIPS);
1478  /* If flipped and vehicle length is odd, we need to adjust the bounding box offset slightly. */
1479  int flip_offs = flipped && (this->gcache.cached_veh_length & 1);
1480 
1481  Direction dir = this->direction;
1482  if (flipped) dir = ReverseDir(dir);
1483 
1484  if (!IsDiagonalDirection(dir)) {
1485  static const int _sign_table[] =
1486  {
1487  /* x, y */
1488  -1, -1, // DIR_N
1489  -1, 1, // DIR_E
1490  1, 1, // DIR_S
1491  1, -1, // DIR_W
1492  };
1493 
1494  int half_shorten = (VEHICLE_LENGTH - this->gcache.cached_veh_length + flipped) / 2;
1495 
1496  /* For all straight directions, move the bound box to the centre of the vehicle, but keep the size. */
1497  this->x_offs -= half_shorten * _sign_table[dir];
1498  this->y_offs -= half_shorten * _sign_table[dir + 1];
1499  this->x_extent += this->x_bb_offs = half_shorten * _sign_table[dir];
1500  this->y_extent += this->y_bb_offs = half_shorten * _sign_table[dir + 1];
1501  } else {
1502  switch (dir) {
1503  /* Shorten southern corner of the bounding box according the vehicle length
1504  * and center the bounding box on the vehicle. */
1505  case DIR_NE:
1506  this->x_offs = 1 - (this->gcache.cached_veh_length + 1) / 2 + flip_offs;
1507  this->x_extent = this->gcache.cached_veh_length - 1;
1508  this->x_bb_offs = -1;
1509  break;
1510 
1511  case DIR_NW:
1512  this->y_offs = 1 - (this->gcache.cached_veh_length + 1) / 2 + flip_offs;
1513  this->y_extent = this->gcache.cached_veh_length - 1;
1514  this->y_bb_offs = -1;
1515  break;
1516 
1517  /* Move northern corner of the bounding box down according to vehicle length
1518  * and center the bounding box on the vehicle. */
1519  case DIR_SW:
1520  this->x_offs = 1 + (this->gcache.cached_veh_length + 1) / 2 - VEHICLE_LENGTH - flip_offs;
1521  this->x_extent = VEHICLE_LENGTH - 1;
1522  this->x_bb_offs = VEHICLE_LENGTH - this->gcache.cached_veh_length - 1;
1523  break;
1524 
1525  case DIR_SE:
1526  this->y_offs = 1 + (this->gcache.cached_veh_length + 1) / 2 - VEHICLE_LENGTH - flip_offs;
1527  this->y_extent = VEHICLE_LENGTH - 1;
1528  this->y_bb_offs = VEHICLE_LENGTH - this->gcache.cached_veh_length - 1;
1529  break;
1530 
1531  default:
1532  NOT_REACHED();
1533  }
1534  }
1535 }
1536 
1541 static void MarkTrainAsStuck(Train *v)
1542 {
1543  if (!HasBit(v->flags, VRF_TRAIN_STUCK)) {
1544  /* It is the first time the problem occurred, set the "train stuck" flag. */
1545  SetBit(v->flags, VRF_TRAIN_STUCK);
1546 
1547  v->wait_counter = 0;
1548 
1549  /* Stop train */
1550  v->cur_speed = 0;
1551  v->subspeed = 0;
1552  v->SetLastSpeed();
1553 
1555  }
1556 }
1557 
1565 static void SwapTrainFlags(uint16_t *swap_flag1, uint16_t *swap_flag2)
1566 {
1567  uint16_t flag1 = *swap_flag1;
1568  uint16_t flag2 = *swap_flag2;
1569 
1570  /* Clear the flags */
1571  ClrBit(*swap_flag1, GVF_GOINGUP_BIT);
1572  ClrBit(*swap_flag1, GVF_GOINGDOWN_BIT);
1573  ClrBit(*swap_flag2, GVF_GOINGUP_BIT);
1574  ClrBit(*swap_flag2, GVF_GOINGDOWN_BIT);
1575 
1576  /* Reverse the rail-flags (if needed) */
1577  if (HasBit(flag1, GVF_GOINGUP_BIT)) {
1578  SetBit(*swap_flag2, GVF_GOINGDOWN_BIT);
1579  } else if (HasBit(flag1, GVF_GOINGDOWN_BIT)) {
1580  SetBit(*swap_flag2, GVF_GOINGUP_BIT);
1581  }
1582  if (HasBit(flag2, GVF_GOINGUP_BIT)) {
1583  SetBit(*swap_flag1, GVF_GOINGDOWN_BIT);
1584  } else if (HasBit(flag2, GVF_GOINGDOWN_BIT)) {
1585  SetBit(*swap_flag1, GVF_GOINGUP_BIT);
1586  }
1587 }
1588 
1594 {
1595  /* Reverse the direction. */
1596  if (v->track != TRACK_BIT_DEPOT) v->direction = ReverseDir(v->direction);
1597 
1598  /* Call the proper EnterTile function unless we are in a wormhole. */
1599  if (v->track != TRACK_BIT_WORMHOLE) {
1600  VehicleEnterTile(v, v->tile, v->x_pos, v->y_pos);
1601  } else {
1602  /* VehicleEnter_TunnelBridge() sets TRACK_BIT_WORMHOLE when the vehicle
1603  * is on the last bit of the bridge head (frame == TILE_SIZE - 1).
1604  * If we were swapped with such a vehicle, we have set TRACK_BIT_WORMHOLE,
1605  * when we shouldn't have. Check if this is the case. */
1606  TileIndex vt = TileVirtXY(v->x_pos, v->y_pos);
1607  if (IsTileType(vt, MP_TUNNELBRIDGE)) {
1608  VehicleEnterTile(v, vt, v->x_pos, v->y_pos);
1609  if (v->track != TRACK_BIT_WORMHOLE && IsBridgeTile(v->tile)) {
1610  /* We have just left the wormhole, possibly set the
1611  * "goingdown" bit. UpdateInclination() can be used
1612  * because we are at the border of the tile. */
1613  v->UpdatePosition();
1614  v->UpdateInclination(true, true);
1615  return;
1616  }
1617  }
1618  }
1619 
1620  v->UpdatePosition();
1621  v->UpdateViewport(true, true);
1622 }
1623 
1630 void ReverseTrainSwapVeh(Train *v, int l, int r)
1631 {
1632  Train *a, *b;
1633 
1634  /* locate vehicles to swap */
1635  for (a = v; l != 0; l--) a = a->Next();
1636  for (b = v; r != 0; r--) b = b->Next();
1637 
1638  if (a != b) {
1639  /* swap the hidden bits */
1640  {
1641  uint16_t tmp = (a->vehstatus & ~VS_HIDDEN) | (b->vehstatus & VS_HIDDEN);
1642  b->vehstatus = (b->vehstatus & ~VS_HIDDEN) | (a->vehstatus & VS_HIDDEN);
1643  a->vehstatus = tmp;
1644  }
1645 
1646  Swap(a->track, b->track);
1647  Swap(a->direction, b->direction);
1648  Swap(a->x_pos, b->x_pos);
1649  Swap(a->y_pos, b->y_pos);
1650  Swap(a->tile, b->tile);
1651  Swap(a->z_pos, b->z_pos);
1652 
1653  SwapTrainFlags(&a->gv_flags, &b->gv_flags);
1654 
1657  } else {
1658  /* Swap GVF_GOINGUP_BIT/GVF_GOINGDOWN_BIT.
1659  * This is a little bit redundant way, a->gv_flags will
1660  * be (re)set twice, but it reduces code duplication */
1661  SwapTrainFlags(&a->gv_flags, &a->gv_flags);
1663  }
1664 }
1665 
1666 
1672 static Vehicle *TrainOnTileEnum(Vehicle *v, void *)
1673 {
1674  return (v->type == VEH_TRAIN) ? v : nullptr;
1675 }
1676 
1684 {
1685  assert(IsLevelCrossingTile(tile));
1686 
1687  return HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum);
1688 }
1689 
1690 
1698 {
1699  if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return nullptr;
1700 
1701  Train *t = Train::From(v);
1702  if (!t->IsFrontEngine()) return nullptr;
1703 
1704  TileIndex tile = *(TileIndex *)data;
1705 
1706  if (TrainApproachingCrossingTile(t) != tile) return nullptr;
1707 
1708  return t;
1709 }
1710 
1711 
1719 {
1720  assert(IsLevelCrossingTile(tile));
1721 
1723  TileIndex tile_from = tile + TileOffsByDiagDir(dir);
1724 
1725  if (HasVehicleOnPos(tile_from, &tile, &TrainApproachingCrossingEnum)) return true;
1726 
1727  dir = ReverseDiagDir(dir);
1728  tile_from = tile + TileOffsByDiagDir(dir);
1729 
1730  return HasVehicleOnPos(tile_from, &tile, &TrainApproachingCrossingEnum);
1731 }
1732 
1738 static inline bool CheckLevelCrossing(TileIndex tile)
1739 {
1740  /* reserved || train on crossing || train approaching crossing */
1741  return HasCrossingReservation(tile) || TrainOnCrossing(tile) || TrainApproachingCrossing(tile);
1742 }
1743 
1751 static void UpdateLevelCrossingTile(TileIndex tile, bool sound, bool force_barred)
1752 {
1753  assert(IsLevelCrossingTile(tile));
1754  bool set_barred;
1755 
1756  /* We force the crossing to be barred when an adjacent crossing is barred, otherwise let it decide for itself. */
1757  set_barred = force_barred || CheckLevelCrossing(tile);
1758 
1759  /* The state has changed */
1760  if (set_barred != IsCrossingBarred(tile)) {
1761  if (set_barred && sound && _settings_client.sound.ambient) SndPlayTileFx(SND_0E_LEVEL_CROSSING, tile);
1762  SetCrossingBarred(tile, set_barred);
1763  MarkTileDirtyByTile(tile);
1764  }
1765 }
1766 
1773 void UpdateLevelCrossing(TileIndex tile, bool sound, bool force_bar)
1774 {
1775  if (!IsLevelCrossingTile(tile)) return;
1776 
1777  bool forced_state = force_bar;
1778 
1779  const Axis axis = GetCrossingRoadAxis(tile);
1780  const DiagDirection dir1 = AxisToDiagDir(axis);
1781  const DiagDirection dir2 = ReverseDiagDir(dir1);
1782 
1783  /* Check if an adjacent crossing is barred. */
1784  for (DiagDirection dir : { dir1, dir2 }) {
1785  for (TileIndex t = tile; !forced_state && t < Map::Size() && IsLevelCrossingTile(t) && GetCrossingRoadAxis(t) == axis; t = TileAddByDiagDir(t, dir)) {
1786  forced_state |= CheckLevelCrossing(t);
1787  }
1788  }
1789 
1790  /* Now that we know whether all tiles in this crossing should be barred or open,
1791  * we need to update those tiles. We start with the tile itself, then look along the road axis. */
1792  UpdateLevelCrossingTile(tile, sound, forced_state);
1793  for (DiagDirection dir : { dir1, dir2 }) {
1794  for (TileIndex t = TileAddByDiagDir(tile, dir); t < Map::Size() && IsLevelCrossingTile(t) && GetCrossingRoadAxis(t) == axis; t = TileAddByDiagDir(t, dir)) {
1795  UpdateLevelCrossingTile(t, sound, forced_state);
1796  }
1797  }
1798 }
1799 
1806 {
1807  const DiagDirection dir1 = AxisToDiagDir(road_axis);
1808  const DiagDirection dir2 = ReverseDiagDir(dir1);
1809  for (DiagDirection dir : { dir1, dir2 }) {
1810  const TileIndex t = TileAddByDiagDir(tile, dir);
1811  if (t < Map::Size() && IsLevelCrossingTile(t) && GetCrossingRoadAxis(t) == road_axis) {
1813  }
1814  }
1815 }
1816 
1823 {
1824  const DiagDirection dir1 = AxisToDiagDir(road_axis);
1825  const DiagDirection dir2 = ReverseDiagDir(dir1);
1826  for (DiagDirection dir : { dir1, dir2 }) {
1827  const TileIndexDiff diff = TileOffsByDiagDir(dir);
1828  bool occupied = false;
1829  for (TileIndex t = tile + diff; t < Map::Size() && IsLevelCrossingTile(t) && GetCrossingRoadAxis(t) == road_axis; t += diff) {
1830  occupied |= CheckLevelCrossing(t);
1831  }
1832  if (occupied) {
1833  /* Mark the immediately adjacent tile dirty */
1834  const TileIndex t = tile + diff;
1835  if (t < Map::Size() && IsLevelCrossingTile(t) && GetCrossingRoadAxis(t) == road_axis) {
1837  }
1838  } else {
1839  /* Unbar the crossing tiles in this direction as necessary */
1840  for (TileIndex t = tile + diff; t < Map::Size() && IsLevelCrossingTile(t) && GetCrossingRoadAxis(t) == road_axis; t += diff) {
1841  if (IsCrossingBarred(t)) {
1842  /* The crossing tile is barred, unbar it and continue to check the next tile */
1843  SetCrossingBarred(t, false);
1845  } else {
1846  /* The crossing tile is already unbarred, mark the tile dirty and stop checking */
1848  break;
1849  }
1850  }
1851  }
1852  }
1853 }
1854 
1860 static inline void MaybeBarCrossingWithSound(TileIndex tile)
1861 {
1862  if (!IsCrossingBarred(tile)) {
1863  SetCrossingReservation(tile, true);
1864  UpdateLevelCrossing(tile, true);
1865  }
1866 }
1867 
1868 
1875 {
1876  Train *base = v;
1877  Train *first = base; // first vehicle to move
1878  Train *last = v->Last(); // last vehicle to move
1879  uint length = CountVehiclesInChain(v);
1880 
1881  while (length > 2) {
1882  last = last->Previous();
1883  first = first->Next();
1884 
1885  int differential = base->CalcNextVehicleOffset() - last->CalcNextVehicleOffset();
1886 
1887  /* do not update images now
1888  * negative differential will be handled in AdvanceWagonsAfterSwap() */
1889  for (int i = 0; i < differential; i++) TrainController(first, last->Next());
1890 
1891  base = first; // == base->Next()
1892  length -= 2;
1893  }
1894 }
1895 
1896 
1903 {
1904  /* first of all, fix the situation when the train was entering a depot */
1905  Train *dep = v; // last vehicle in front of just left depot
1906  while (dep->Next() != nullptr && (dep->track == TRACK_BIT_DEPOT || dep->Next()->track != TRACK_BIT_DEPOT)) {
1907  dep = dep->Next(); // find first vehicle outside of a depot, with next vehicle inside a depot
1908  }
1909 
1910  Train *leave = dep->Next(); // first vehicle in a depot we are leaving now
1911 
1912  if (leave != nullptr) {
1913  /* 'pull' next wagon out of the depot, so we won't miss it (it could stay in depot forever) */
1914  int d = TicksToLeaveDepot(dep);
1915 
1916  if (d <= 0) {
1917  leave->vehstatus &= ~VS_HIDDEN; // move it out of the depot
1918  leave->track = TrackToTrackBits(GetRailDepotTrack(leave->tile));
1919  for (int i = 0; i >= d; i--) TrainController(leave, nullptr); // maybe move it, and maybe let another wagon leave
1920  }
1921  } else {
1922  dep = nullptr; // no vehicle in a depot, so no vehicle leaving a depot
1923  }
1924 
1925  Train *base = v;
1926  Train *first = base; // first vehicle to move
1927  Train *last = v->Last(); // last vehicle to move
1928  uint length = CountVehiclesInChain(v);
1929 
1930  /* We have to make sure all wagons that leave a depot because of train reversing are moved correctly
1931  * they have already correct spacing, so we have to make sure they are moved how they should */
1932  bool nomove = (dep == nullptr); // If there is no vehicle leaving a depot, limit the number of wagons moved immediately.
1933 
1934  while (length > 2) {
1935  /* we reached vehicle (originally) in front of a depot, stop now
1936  * (we would move wagons that are already moved with new wagon length). */
1937  if (base == dep) break;
1938 
1939  /* the last wagon was that one leaving a depot, so do not move it anymore */
1940  if (last == dep) nomove = true;
1941 
1942  last = last->Previous();
1943  first = first->Next();
1944 
1945  int differential = last->CalcNextVehicleOffset() - base->CalcNextVehicleOffset();
1946 
1947  /* do not update images now */
1948  for (int i = 0; i < differential; i++) TrainController(first, (nomove ? last->Next() : nullptr));
1949 
1950  base = first; // == base->Next()
1951  length -= 2;
1952  }
1953 }
1954 
1955 static bool IsWholeTrainInsideDepot(const Train *v)
1956 {
1957  for (const Train *u = v; u != nullptr; u = u->Next()) {
1958  if (u->track != TRACK_BIT_DEPOT || u->tile != v->tile) return false;
1959  }
1960  return true;
1961 }
1962 
1968 {
1969  if (IsRailDepotTile(v->tile)) {
1970  if (IsWholeTrainInsideDepot(v)) return;
1972  }
1973 
1974  /* Clear path reservation in front if train is not stuck. */
1975  if (!HasBit(v->flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(v);
1976 
1977  /* Check if we were approaching a rail/road-crossing */
1979 
1980  /* count number of vehicles */
1981  int r = CountVehiclesInChain(v) - 1; // number of vehicles - 1
1982 
1984 
1985  /* swap start<>end, start+1<>end-1, ... */
1986  int l = 0;
1987  do {
1988  ReverseTrainSwapVeh(v, l++, r--);
1989  } while (l <= r);
1990 
1992 
1993  if (IsRailDepotTile(v->tile)) {
1995  }
1996 
1997  ToggleBit(v->flags, VRF_TOGGLE_REVERSE);
1998 
1999  ClrBit(v->flags, VRF_REVERSING);
2000 
2001  /* recalculate cached data */
2003 
2004  /* update all images */
2005  for (Train *u = v; u != nullptr; u = u->Next()) u->UpdateViewport(false, false);
2006 
2007  /* update crossing we were approaching */
2008  if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing);
2009 
2010  /* maybe we are approaching crossing now, after reversal */
2011  crossing = TrainApproachingCrossingTile(v);
2012  if (crossing != INVALID_TILE) MaybeBarCrossingWithSound(crossing);
2013 
2014  /* If we are inside a depot after reversing, don't bother with path reserving. */
2015  if (v->track == TRACK_BIT_DEPOT) {
2016  /* Can't be stuck here as inside a depot is always a safe tile. */
2018  ClrBit(v->flags, VRF_TRAIN_STUCK);
2019  return;
2020  }
2021 
2022  /* VehicleExitDir does not always produce the desired dir for depots and
2023  * tunnels/bridges that is needed for UpdateSignalsOnSegment. */
2024  DiagDirection dir = VehicleExitDir(v->direction, v->track);
2026 
2028  /* If we are currently on a tile with conventional signals, we can't treat the
2029  * current tile as a safe tile or we would enter a PBS block without a reservation. */
2030  bool first_tile_okay = !(IsTileType(v->tile, MP_RAILWAY) &&
2032  !IsPbsSignal(GetSignalType(v->tile, FindFirstTrack(v->track))));
2033 
2034  /* If we are on a depot tile facing outwards, do not treat the current tile as safe. */
2035  if (IsRailDepotTile(v->tile) && TrackdirToExitdir(v->GetVehicleTrackdir()) == GetRailDepotDirection(v->tile)) first_tile_okay = false;
2036 
2038  if (TryPathReserve(v, false, first_tile_okay)) {
2039  /* Do a look-ahead now in case our current tile was already a safe tile. */
2040  CheckNextTrainTile(v);
2041  } else if (v->current_order.GetType() != OT_LOADING) {
2042  /* Do not wait for a way out when we're still loading */
2043  MarkTrainAsStuck(v);
2044  }
2045  } else if (HasBit(v->flags, VRF_TRAIN_STUCK)) {
2046  /* A train not inside a PBS block can't be stuck. */
2047  ClrBit(v->flags, VRF_TRAIN_STUCK);
2048  v->wait_counter = 0;
2049  }
2050 }
2051 
2059 CommandCost CmdReverseTrainDirection(DoCommandFlag flags, VehicleID veh_id, bool reverse_single_veh)
2060 {
2061  Train *v = Train::GetIfValid(veh_id);
2062  if (v == nullptr) return CMD_ERROR;
2063 
2064  CommandCost ret = CheckOwnership(v->owner);
2065  if (ret.Failed()) return ret;
2066 
2067  if (reverse_single_veh) {
2068  /* turn a single unit around */
2069 
2071  return_cmd_error(STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE_MULTIPLE_UNITS);
2072  }
2073 
2074  Train *front = v->First();
2075  /* make sure the vehicle is stopped in the depot */
2076  if (!front->IsStoppedInDepot()) {
2077  return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT);
2078  }
2079 
2080  if (flags & DC_EXEC) {
2081  ToggleBit(v->flags, VRF_REVERSE_DIRECTION);
2082 
2083  front->ConsistChanged(CCF_ARRANGE);
2088  }
2089  } else {
2090  /* turn the whole train around */
2091  if (!v->IsPrimaryVehicle()) return CMD_ERROR;
2092  if ((v->vehstatus & VS_CRASHED) || v->breakdown_ctr != 0) return CMD_ERROR;
2093 
2094  if (flags & DC_EXEC) {
2095  /* Properly leave the station if we are loading and won't be loading anymore */
2096  if (v->current_order.IsType(OT_LOADING)) {
2097  const Vehicle *last = v;
2098  while (last->Next() != nullptr) last = last->Next();
2099 
2100  /* not a station || different station --> leave the station */
2101  if (!IsTileType(last->tile, MP_STATION) || GetStationIndex(last->tile) != GetStationIndex(v->tile)) {
2102  v->LeaveStation();
2103  }
2104  }
2105 
2106  /* We cancel any 'skip signal at dangers' here */
2107  v->force_proceed = TFP_NONE;
2109 
2110  if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && v->cur_speed != 0) {
2111  ToggleBit(v->flags, VRF_REVERSING);
2112  } else {
2113  v->cur_speed = 0;
2114  v->SetLastSpeed();
2117  }
2118 
2119  /* Unbunching data is no longer valid. */
2120  v->ResetDepotUnbunching();
2121  }
2122  }
2123  return CommandCost();
2124 }
2125 
2133 {
2134  Train *t = Train::GetIfValid(veh_id);
2135  if (t == nullptr) return CMD_ERROR;
2136 
2137  if (!t->IsPrimaryVehicle()) return CMD_ERROR;
2138 
2139  CommandCost ret = CheckOwnership(t->owner);
2140  if (ret.Failed()) return ret;
2141 
2142 
2143  if (flags & DC_EXEC) {
2144  /* If we are forced to proceed, cancel that order.
2145  * If we are marked stuck we would want to force the train
2146  * to proceed to the next signal. In the other cases we
2147  * would like to pass the signal at danger and run till the
2148  * next signal we encounter. */
2149  t->force_proceed = t->force_proceed == TFP_SIGNAL ? TFP_NONE : HasBit(t->flags, VRF_TRAIN_STUCK) || t->IsChainInDepot() ? TFP_STUCK : TFP_SIGNAL;
2151 
2152  /* Unbunching data is no longer valid. */
2153  t->ResetDepotUnbunching();
2154  }
2155 
2156  return CommandCost();
2157 }
2158 
2166 static FindDepotData FindClosestTrainDepot(Train *v, int max_distance)
2167 {
2168  assert(!(v->vehstatus & VS_CRASHED));
2169 
2170  return YapfTrainFindNearestDepot(v, max_distance);
2171 }
2172 
2174 {
2175  FindDepotData tfdd = FindClosestTrainDepot(this, 0);
2176  if (tfdd.best_length == UINT_MAX) return ClosestDepot();
2177 
2178  return ClosestDepot(tfdd.tile, GetDepotIndex(tfdd.tile), tfdd.reverse);
2179 }
2180 
2182 void Train::PlayLeaveStationSound(bool force) const
2183 {
2184  static const SoundFx sfx[] = {
2190  };
2191 
2192  if (PlayVehicleSound(this, VSE_START, force)) return;
2193 
2194  SndPlayVehicleFx(sfx[RailVehInfo(this->engine_type)->engclass], this);
2195 }
2196 
2201 static void CheckNextTrainTile(Train *v)
2202 {
2203  /* Don't do any look-ahead if path_backoff_interval is 255. */
2204  if (_settings_game.pf.path_backoff_interval == 255) return;
2205 
2206  /* Exit if we are inside a depot. */
2207  if (v->track == TRACK_BIT_DEPOT) return;
2208 
2209  switch (v->current_order.GetType()) {
2210  /* Exit if we reached our destination depot. */
2211  case OT_GOTO_DEPOT:
2212  if (v->tile == v->dest_tile) return;
2213  break;
2214 
2215  case OT_GOTO_WAYPOINT:
2216  /* If we reached our waypoint, make sure we see that. */
2218  break;
2219 
2220  case OT_NOTHING:
2221  case OT_LEAVESTATION:
2222  case OT_LOADING:
2223  /* Exit if the current order doesn't have a destination, but the train has orders. */
2224  if (v->GetNumOrders() > 0) return;
2225  break;
2226 
2227  default:
2228  break;
2229  }
2230  /* Exit if we are on a station tile and are going to stop. */
2232 
2233  Trackdir td = v->GetVehicleTrackdir();
2234 
2235  /* On a tile with a red non-pbs signal, don't look ahead. */
2236  if (IsTileType(v->tile, MP_RAILWAY) && HasSignalOnTrackdir(v->tile, td) &&
2237  !IsPbsSignal(GetSignalType(v->tile, TrackdirToTrack(td))) &&
2238  GetSignalStateByTrackdir(v->tile, td) == SIGNAL_STATE_RED) return;
2239 
2240  CFollowTrackRail ft(v);
2241  if (!ft.Follow(v->tile, td)) return;
2242 
2244  /* Next tile is not reserved. */
2247  /* If the next tile is a PBS signal, try to make a reservation. */
2250  tracks &= ~TrackCrossesTracks(TrackdirToTrack(ft.old_td));
2251  }
2252  ChooseTrainTrack(v, ft.new_tile, ft.exitdir, tracks, false, nullptr, false);
2253  }
2254  }
2255  }
2256 }
2257 
2264 {
2265  /* bail out if not all wagons are in the same depot or not in a depot at all */
2266  for (const Train *u = v; u != nullptr; u = u->Next()) {
2267  if (u->track != TRACK_BIT_DEPOT || u->tile != v->tile) return false;
2268  }
2269 
2270  /* if the train got no power, then keep it in the depot */
2271  if (v->gcache.cached_power == 0) {
2272  v->vehstatus |= VS_STOPPED;
2274  return true;
2275  }
2276 
2277  /* Check if we should wait here for unbunching. */
2278  if (v->IsWaitingForUnbunching()) return true;
2279 
2280  SigSegState seg_state;
2281 
2282  if (v->force_proceed == TFP_NONE) {
2283  /* force proceed was not pressed */
2284  if (++v->wait_counter < 37) {
2286  return true;
2287  }
2288 
2289  v->wait_counter = 0;
2290 
2292  if (seg_state == SIGSEG_FULL || HasDepotReservation(v->tile)) {
2293  /* Full and no PBS signal in block or depot reserved, can't exit. */
2295  return true;
2296  }
2297  } else {
2299  }
2300 
2301  /* We are leaving a depot, but have to go to the exact same one; re-enter. */
2302  if (v->current_order.IsType(OT_GOTO_DEPOT) && v->tile == v->dest_tile) {
2303  /* Service when depot has no reservation. */
2305  return true;
2306  }
2307 
2308  /* Only leave when we can reserve a path to our destination. */
2309  if (seg_state == SIGSEG_PBS && !TryPathReserve(v) && v->force_proceed == TFP_NONE) {
2310  /* No path and no force proceed. */
2312  MarkTrainAsStuck(v);
2313  return true;
2314  }
2315 
2316  SetDepotReservation(v->tile, true);
2318 
2320  v->LeaveUnbunchingDepot();
2321  v->PlayLeaveStationSound();
2323 
2324  v->track = TRACK_BIT_X;
2325  if (v->direction & 2) v->track = TRACK_BIT_Y;
2326 
2327  v->vehstatus &= ~VS_HIDDEN;
2328  v->cur_speed = 0;
2329 
2330  v->UpdateViewport(true, true);
2331  v->UpdatePosition();
2333  v->UpdateAcceleration();
2335 
2336  return false;
2337 }
2338 
2345 static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_dir)
2346 {
2347  DiagDirection dir = TrackdirToExitdir(track_dir);
2348 
2349  if (IsTileType(tile, MP_TUNNELBRIDGE)) {
2350  /* Are we just leaving a tunnel/bridge? */
2351  if (GetTunnelBridgeDirection(tile) == ReverseDiagDir(dir)) {
2352  TileIndex end = GetOtherTunnelBridgeEnd(tile);
2353 
2354  if (TunnelBridgeIsFree(tile, end, v).Succeeded()) {
2355  /* Free the reservation only if no other train is on the tiles. */
2356  SetTunnelBridgeReservation(tile, false);
2357  SetTunnelBridgeReservation(end, false);
2358 
2360  if (IsBridge(tile)) {
2361  MarkBridgeDirty(tile);
2362  } else {
2363  MarkTileDirtyByTile(tile);
2364  MarkTileDirtyByTile(end);
2365  }
2366  }
2367  }
2368  }
2369  } else if (IsRailStationTile(tile)) {
2370  TileIndex new_tile = TileAddByDiagDir(tile, dir);
2371  /* If the new tile is not a further tile of the same station, we
2372  * clear the reservation for the whole platform. */
2373  if (!IsCompatibleTrainStationTile(new_tile, tile)) {
2375  }
2376  } else {
2377  /* Any other tile */
2378  UnreserveRailTrack(tile, TrackdirToTrack(track_dir));
2379  }
2380 }
2381 
2387 {
2388  assert(v->IsFrontEngine());
2389 
2390  TileIndex tile = v->tile;
2391  Trackdir td = v->GetVehicleTrackdir();
2392  bool free_tile = !(IsRailStationTile(v->tile) || IsTileType(v->tile, MP_TUNNELBRIDGE));
2393  StationID station_id = IsRailStationTile(v->tile) ? GetStationIndex(v->tile) : INVALID_STATION;
2394 
2395  /* Can't be holding a reservation if we enter a depot. */
2396  if (IsRailDepotTile(tile) && TrackdirToExitdir(td) != GetRailDepotDirection(tile)) return;
2397  if (v->track == TRACK_BIT_DEPOT) {
2398  /* Front engine is in a depot. We enter if some part is not in the depot. */
2399  for (const Train *u = v; u != nullptr; u = u->Next()) {
2400  if (u->track != TRACK_BIT_DEPOT || u->tile != v->tile) return;
2401  }
2402  }
2403  /* Don't free reservation if it's not ours. */
2405 
2407  while (ft.Follow(tile, td)) {
2408  tile = ft.new_tile;
2410  td = RemoveFirstTrackdir(&bits);
2411  assert(bits == TRACKDIR_BIT_NONE);
2412 
2413  if (!IsValidTrackdir(td)) break;
2414 
2415  if (IsTileType(tile, MP_RAILWAY)) {
2416  if (HasSignalOnTrackdir(tile, td) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(td)))) {
2417  /* Conventional signal along trackdir: remove reservation and stop. */
2419  break;
2420  }
2421  if (HasPbsSignalOnTrackdir(tile, td)) {
2422  if (GetSignalStateByTrackdir(tile, td) == SIGNAL_STATE_RED) {
2423  /* Red PBS signal? Can't be our reservation, would be green then. */
2424  break;
2425  } else {
2426  /* Turn the signal back to red. */
2428  MarkTileDirtyByTile(tile);
2429  }
2430  } else if (HasPbsSignalOnTrackdir(tile, ReverseTrackdir(td))) {
2431  /* Reservation passes an opposing path signal. Mark signal for update to re-establish the proper default state. */
2433  } else if (HasSignalOnTrackdir(tile, ReverseTrackdir(td)) && IsOnewaySignal(tile, TrackdirToTrack(td))) {
2434  break;
2435  }
2436  }
2437 
2438  /* Don't free first station/bridge/tunnel if we are on it. */
2439  if (free_tile || (!(ft.is_station && GetStationIndex(ft.new_tile) == station_id) && !ft.is_tunnel && !ft.is_bridge)) ClearPathReservation(v, tile, td);
2440 
2441  free_tile = true;
2442  }
2443 
2445 }
2446 
2447 static const uint8_t _initial_tile_subcoord[6][4][3] = {
2448 {{ 15, 8, 1 }, { 0, 0, 0 }, { 0, 8, 5 }, { 0, 0, 0 }},
2449 {{ 0, 0, 0 }, { 8, 0, 3 }, { 0, 0, 0 }, { 8, 15, 7 }},
2450 {{ 0, 0, 0 }, { 7, 0, 2 }, { 0, 7, 6 }, { 0, 0, 0 }},
2451 {{ 15, 8, 2 }, { 0, 0, 0 }, { 0, 0, 0 }, { 8, 15, 6 }},
2452 {{ 15, 7, 0 }, { 8, 0, 4 }, { 0, 0, 0 }, { 0, 0, 0 }},
2453 {{ 0, 0, 0 }, { 0, 0, 0 }, { 0, 8, 4 }, { 7, 15, 0 }},
2454 };
2455 
2469 static Track DoTrainPathfind(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool do_track_reservation, PBSTileInfo *dest, TileIndex *final_dest)
2470 {
2471  if (final_dest != nullptr) *final_dest = INVALID_TILE;
2472  return YapfTrainChooseTrack(v, tile, enterdir, tracks, path_found, do_track_reservation, dest, final_dest);
2473 }
2474 
2480 static PBSTileInfo ExtendTrainReservation(const Train *v, TrackBits *new_tracks, DiagDirection *enterdir)
2481 {
2482  PBSTileInfo origin = FollowTrainReservation(v);
2483 
2484  CFollowTrackRail ft(v);
2485 
2486  std::vector<std::pair<TileIndex, Trackdir>> signals_set_to_red;
2487 
2488  TileIndex tile = origin.tile;
2489  Trackdir cur_td = origin.trackdir;
2490  while (ft.Follow(tile, cur_td)) {
2492  /* Possible signal tile. */
2494  }
2495 
2498  if (ft.new_td_bits == TRACKDIR_BIT_NONE) break;
2499  }
2500 
2501  /* Station, depot or waypoint are a possible target. */
2502  bool target_seen = ft.is_station || (IsTileType(ft.new_tile, MP_RAILWAY) && !IsPlainRail(ft.new_tile));
2503  if (target_seen || KillFirstBit(ft.new_td_bits) != TRACKDIR_BIT_NONE) {
2504  /* Choice found or possible target encountered.
2505  * On finding a possible target, we need to stop and let the pathfinder handle the
2506  * remaining path. This is because we don't know if this target is in one of our
2507  * orders, so we might cause pathfinding to fail later on if we find a choice.
2508  * This failure would cause a bogous call to TryReserveSafePath which might reserve
2509  * a wrong path not leading to our next destination. */
2511 
2512  /* If we did skip some tiles, backtrack to the first skipped tile so the pathfinder
2513  * actually starts its search at the first unreserved tile. */
2514  if (ft.tiles_skipped != 0) ft.new_tile -= TileOffsByDiagDir(ft.exitdir) * ft.tiles_skipped;
2515 
2516  /* Choice found, path valid but not okay. Save info about the choice tile as well. */
2517  if (new_tracks != nullptr) *new_tracks = TrackdirBitsToTrackBits(ft.new_td_bits);
2518  if (enterdir != nullptr) *enterdir = ft.exitdir;
2519  return PBSTileInfo(ft.new_tile, ft.old_td, false);
2520  }
2521 
2522  tile = ft.new_tile;
2523  cur_td = FindFirstTrackdir(ft.new_td_bits);
2524 
2525  Trackdir rev_td = ReverseTrackdir(cur_td);
2526  if (IsSafeWaitingPosition(v, tile, cur_td, true, _settings_game.pf.forbid_90_deg)) {
2527  bool wp_free = IsWaitingPositionFree(v, tile, cur_td, _settings_game.pf.forbid_90_deg);
2528  if (!(wp_free && TryReserveRailTrack(tile, TrackdirToTrack(cur_td)))) break;
2529  /* Green path signal opposing the path? Turn to red. */
2530  if (HasPbsSignalOnTrackdir(tile, rev_td) && GetSignalStateByTrackdir(tile, rev_td) == SIGNAL_STATE_GREEN) {
2531  signals_set_to_red.emplace_back(tile, rev_td);
2533  MarkTileDirtyByTile(tile);
2534  }
2535  /* Safe position is all good, path valid and okay. */
2536  return PBSTileInfo(tile, cur_td, true);
2537  }
2538 
2539  if (!TryReserveRailTrack(tile, TrackdirToTrack(cur_td))) break;
2540 
2541  /* Green path signal opposing the path? Turn to red. */
2542  if (HasPbsSignalOnTrackdir(tile, rev_td) && GetSignalStateByTrackdir(tile, rev_td) == SIGNAL_STATE_GREEN) {
2543  signals_set_to_red.emplace_back(tile, rev_td);
2545  MarkTileDirtyByTile(tile);
2546  }
2547  }
2548 
2549  if (ft.err == CFollowTrackRail::EC_OWNER || ft.err == CFollowTrackRail::EC_NO_WAY) {
2550  /* End of line, path valid and okay. */
2551  return PBSTileInfo(ft.old_tile, ft.old_td, true);
2552  }
2553 
2554  /* Sorry, can't reserve path, back out. */
2555  tile = origin.tile;
2556  cur_td = origin.trackdir;
2557  TileIndex stopped = ft.old_tile;
2558  Trackdir stopped_td = ft.old_td;
2559  while (tile != stopped || cur_td != stopped_td) {
2560  if (!ft.Follow(tile, cur_td)) break;
2561 
2564  assert(ft.new_td_bits != TRACKDIR_BIT_NONE);
2565  }
2567 
2568  tile = ft.new_tile;
2569  cur_td = FindFirstTrackdir(ft.new_td_bits);
2570 
2571  UnreserveRailTrack(tile, TrackdirToTrack(cur_td));
2572  }
2573 
2574  /* Re-instate green signals we turned to red. */
2575  for (auto [sig_tile, td] : signals_set_to_red) {
2577  }
2578 
2579  /* Path invalid. */
2580  return PBSTileInfo();
2581 }
2582 
2593 static bool TryReserveSafeTrack(const Train *v, TileIndex tile, Trackdir td, bool override_railtype)
2594 {
2595  return YapfTrainFindNearestSafeTile(v, tile, td, override_railtype);
2596 }
2597 
2600 private:
2601  Train *v;
2602  Order old_order;
2603  TileIndex old_dest_tile;
2604  StationID old_last_station_visited;
2605  VehicleOrderID index;
2606  bool suppress_implicit_orders;
2607  bool restored;
2608 
2609 public:
2610  VehicleOrderSaver(Train *_v) :
2611  v(_v),
2612  old_order(_v->current_order),
2613  old_dest_tile(_v->dest_tile),
2614  old_last_station_visited(_v->last_station_visited),
2615  index(_v->cur_real_order_index),
2616  suppress_implicit_orders(HasBit(_v->gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS)),
2617  restored(false)
2618  {
2619  }
2620 
2624  void Restore()
2625  {
2626  this->v->current_order = this->old_order;
2627  this->v->dest_tile = this->old_dest_tile;
2628  this->v->last_station_visited = this->old_last_station_visited;
2629  AssignBit(this->v->gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS, suppress_implicit_orders);
2630  this->restored = true;
2631  }
2632 
2637  {
2638  if (!this->restored) this->Restore();
2639  }
2640 
2646  bool SwitchToNextOrder(bool skip_first)
2647  {
2648  if (this->v->GetNumOrders() == 0) return false;
2649 
2650  if (skip_first) ++this->index;
2651 
2652  int depth = 0;
2653 
2654  do {
2655  /* Wrap around. */
2656  if (this->index >= this->v->GetNumOrders()) this->index = 0;
2657 
2658  Order *order = this->v->GetOrder(this->index);
2659  assert(order != nullptr);
2660 
2661  switch (order->GetType()) {
2662  case OT_GOTO_DEPOT:
2663  /* Skip service in depot orders when the train doesn't need service. */
2664  if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !this->v->NeedsServicing()) break;
2665  [[fallthrough]];
2666  case OT_GOTO_STATION:
2667  case OT_GOTO_WAYPOINT:
2668  this->v->current_order = *order;
2669  return UpdateOrderDest(this->v, order, 0, true);
2670  case OT_CONDITIONAL: {
2671  VehicleOrderID next = ProcessConditionalOrder(order, this->v);
2672  if (next != INVALID_VEH_ORDER_ID) {
2673  depth++;
2674  this->index = next;
2675  /* Don't increment next, so no break here. */
2676  continue;
2677  }
2678  break;
2679  }
2680  default:
2681  break;
2682  }
2683  /* Don't increment inside the while because otherwise conditional
2684  * orders can lead to an infinite loop. */
2685  ++this->index;
2686  depth++;
2687  } while (this->index != this->v->cur_real_order_index && depth < this->v->GetNumOrders());
2688 
2689  return false;
2690  }
2691 };
2692 
2693 /* choose a track */
2694 static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck)
2695 {
2696  Track best_track = INVALID_TRACK;
2697  bool do_track_reservation = _settings_game.pf.reserve_paths || force_res;
2698  bool changed_signal = false;
2699  TileIndex final_dest = INVALID_TILE;
2700 
2701  assert((tracks & ~TRACK_BIT_MASK) == 0);
2702 
2703  if (got_reservation != nullptr) *got_reservation = false;
2704 
2705  /* Don't use tracks here as the setting to forbid 90 deg turns might have been switched between reservation and now. */
2706  TrackBits res_tracks = (TrackBits)(GetReservedTrackbits(tile) & DiagdirReachesTracks(enterdir));
2707  /* Do we have a suitable reserved track? */
2708  if (res_tracks != TRACK_BIT_NONE) return FindFirstTrack(res_tracks);
2709 
2710  /* Quick return in case only one possible track is available */
2711  if (KillFirstBit(tracks) == TRACK_BIT_NONE) {
2712  Track track = FindFirstTrack(tracks);
2713  /* We need to check for signals only here, as a junction tile can't have signals. */
2714  if (track != INVALID_TRACK && HasPbsSignalOnTrackdir(tile, TrackEnterdirToTrackdir(track, enterdir))) {
2715  do_track_reservation = true;
2716  changed_signal = true;
2718  } else if (!do_track_reservation) {
2719  return track;
2720  }
2721  best_track = track;
2722  }
2723 
2724  PBSTileInfo res_dest(tile, INVALID_TRACKDIR, false);
2725  DiagDirection dest_enterdir = enterdir;
2726  if (do_track_reservation) {
2727  res_dest = ExtendTrainReservation(v, &tracks, &dest_enterdir);
2728  if (res_dest.tile == INVALID_TILE) {
2729  /* Reservation failed? */
2730  if (mark_stuck) MarkTrainAsStuck(v);
2731  if (changed_signal) SetSignalStateByTrackdir(tile, TrackEnterdirToTrackdir(best_track, enterdir), SIGNAL_STATE_RED);
2732  return FindFirstTrack(tracks);
2733  }
2734  if (res_dest.okay) {
2735  /* Got a valid reservation that ends at a safe target, quick exit. */
2736  if (got_reservation != nullptr) *got_reservation = true;
2737  if (changed_signal) MarkTileDirtyByTile(tile);
2739  return best_track;
2740  }
2741 
2742  /* Check if the train needs service here, so it has a chance to always find a depot.
2743  * Also check if the current order is a service order so we don't reserve a path to
2744  * the destination but instead to the next one if service isn't needed. */
2746  if (v->current_order.IsType(OT_DUMMY) || v->current_order.IsType(OT_CONDITIONAL) || v->current_order.IsType(OT_GOTO_DEPOT)) ProcessOrders(v);
2747  }
2748 
2749  /* Save the current train order. The destructor will restore the old order on function exit. */
2750  VehicleOrderSaver orders(v);
2751 
2752  /* If the current tile is the destination of the current order and
2753  * a reservation was requested, advance to the next order.
2754  * Don't advance on a depot order as depots are always safe end points
2755  * for a path and no look-ahead is necessary. This also avoids a
2756  * problem with depot orders not part of the order list when the
2757  * order list itself is empty. */
2758  if (v->current_order.IsType(OT_LEAVESTATION)) {
2759  orders.SwitchToNextOrder(false);
2760  } else if (v->current_order.IsType(OT_LOADING) || (!v->current_order.IsType(OT_GOTO_DEPOT) && (
2761  v->current_order.IsType(OT_GOTO_STATION) ?
2763  v->tile == v->dest_tile))) {
2764  orders.SwitchToNextOrder(true);
2765  }
2766 
2767  if (res_dest.tile != INVALID_TILE && !res_dest.okay) {
2768  /* Pathfinders are able to tell that route was only 'guessed'. */
2769  bool path_found = true;
2770  TileIndex new_tile = res_dest.tile;
2771 
2772  Track next_track = DoTrainPathfind(v, new_tile, dest_enterdir, tracks, path_found, do_track_reservation, &res_dest, &final_dest);
2773  if (new_tile == tile) best_track = next_track;
2774  v->HandlePathfindingResult(path_found);
2775  }
2776 
2777  /* No track reservation requested -> finished. */
2778  if (!do_track_reservation) return best_track;
2779 
2780  /* A path was found, but could not be reserved. */
2781  if (res_dest.tile != INVALID_TILE && !res_dest.okay) {
2782  if (mark_stuck) MarkTrainAsStuck(v);
2784  return best_track;
2785  }
2786 
2787  /* No possible reservation target found, we are probably lost. */
2788  if (res_dest.tile == INVALID_TILE) {
2789  /* Try to find any safe destination. */
2790  PBSTileInfo origin = FollowTrainReservation(v);
2791  if (TryReserveSafeTrack(v, origin.tile, origin.trackdir, false)) {
2792  TrackBits res = GetReservedTrackbits(tile) & DiagdirReachesTracks(enterdir);
2793  best_track = FindFirstTrack(res);
2795  if (got_reservation != nullptr) *got_reservation = true;
2796  if (changed_signal) MarkTileDirtyByTile(tile);
2797  } else {
2799  if (mark_stuck) MarkTrainAsStuck(v);
2800  }
2801  return best_track;
2802  }
2803 
2804  if (got_reservation != nullptr) *got_reservation = true;
2805 
2806  /* Reservation target found and free, check if it is safe. */
2807  while (!IsSafeWaitingPosition(v, res_dest.tile, res_dest.trackdir, true, _settings_game.pf.forbid_90_deg)) {
2808  /* Extend reservation until we have found a safe position. */
2809  DiagDirection exitdir = TrackdirToExitdir(res_dest.trackdir);
2810  TileIndex next_tile = TileAddByDiagDir(res_dest.tile, exitdir);
2812  if (Rail90DegTurnDisallowed(GetTileRailType(res_dest.tile), GetTileRailType(next_tile))) {
2813  reachable &= ~TrackCrossesTracks(TrackdirToTrack(res_dest.trackdir));
2814  }
2815 
2816  /* Get next order with destination. */
2817  if (orders.SwitchToNextOrder(true)) {
2818  PBSTileInfo cur_dest;
2819  bool path_found;
2820  DoTrainPathfind(v, next_tile, exitdir, reachable, path_found, true, &cur_dest, nullptr);
2821  if (cur_dest.tile != INVALID_TILE) {
2822  res_dest = cur_dest;
2823  if (res_dest.okay) continue;
2824  /* Path found, but could not be reserved. */
2826  if (mark_stuck) MarkTrainAsStuck(v);
2827  if (got_reservation != nullptr) *got_reservation = false;
2828  changed_signal = false;
2829  break;
2830  }
2831  }
2832  /* No order or no safe position found, try any position. */
2833  if (!TryReserveSafeTrack(v, res_dest.tile, res_dest.trackdir, true)) {
2835  if (mark_stuck) MarkTrainAsStuck(v);
2836  if (got_reservation != nullptr) *got_reservation = false;
2837  changed_signal = false;
2838  }
2839  break;
2840  }
2841 
2843 
2844  if (changed_signal) MarkTileDirtyByTile(tile);
2845 
2846  orders.Restore();
2847  if (v->current_order.IsType(OT_GOTO_DEPOT) &&
2849  final_dest != INVALID_TILE && IsRailDepotTile(final_dest)) {
2850  v->current_order.SetDestination(GetDepotIndex(final_dest));
2851  v->dest_tile = final_dest;
2853  }
2854 
2855  return best_track;
2856 }
2857 
2866 bool TryPathReserve(Train *v, bool mark_as_stuck, bool first_tile_okay)
2867 {
2868  assert(v->IsFrontEngine());
2869 
2870  /* We have to handle depots specially as the track follower won't look
2871  * at the depot tile itself but starts from the next tile. If we are still
2872  * inside the depot, a depot reservation can never be ours. */
2873  if (v->track == TRACK_BIT_DEPOT) {
2874  if (HasDepotReservation(v->tile)) {
2875  if (mark_as_stuck) MarkTrainAsStuck(v);
2876  return false;
2877  } else {
2878  /* Depot not reserved, but the next tile might be. */
2880  if (HasReservedTracks(next_tile, DiagdirReachesTracks(GetRailDepotDirection(v->tile)))) return false;
2881  }
2882  }
2883 
2884  Vehicle *other_train = nullptr;
2885  PBSTileInfo origin = FollowTrainReservation(v, &other_train);
2886  /* The path we are driving on is already blocked by some other train.
2887  * This can only happen in certain situations when mixing path and
2888  * block signals or when changing tracks and/or signals.
2889  * Exit here as doing any further reservations will probably just
2890  * make matters worse. */
2891  if (other_train != nullptr && other_train->index != v->index) {
2892  if (mark_as_stuck) MarkTrainAsStuck(v);
2893  return false;
2894  }
2895  /* If we have a reserved path and the path ends at a safe tile, we are finished already. */
2896  if (origin.okay && (v->tile != origin.tile || first_tile_okay)) {
2897  /* Can't be stuck then. */
2899  ClrBit(v->flags, VRF_TRAIN_STUCK);
2900  return true;
2901  }
2902 
2903  /* If we are in a depot, tentatively reserve the depot. */
2904  if (v->track == TRACK_BIT_DEPOT) {
2905  SetDepotReservation(v->tile, true);
2907  }
2908 
2909  DiagDirection exitdir = TrackdirToExitdir(origin.trackdir);
2910  TileIndex new_tile = TileAddByDiagDir(origin.tile, exitdir);
2912 
2914 
2915  bool res_made = false;
2916  ChooseTrainTrack(v, new_tile, exitdir, reachable, true, &res_made, mark_as_stuck);
2917 
2918  if (!res_made) {
2919  /* Free the depot reservation as well. */
2920  if (v->track == TRACK_BIT_DEPOT) SetDepotReservation(v->tile, false);
2921  return false;
2922  }
2923 
2924  if (HasBit(v->flags, VRF_TRAIN_STUCK)) {
2925  v->wait_counter = 0;
2927  }
2928  ClrBit(v->flags, VRF_TRAIN_STUCK);
2929  return true;
2930 }
2931 
2932 
2933 static bool CheckReverseTrain(const Train *v)
2934 {
2936  v->track == TRACK_BIT_DEPOT || v->track == TRACK_BIT_WORMHOLE ||
2937  !(v->direction & 1)) {
2938  return false;
2939  }
2940 
2941  assert(v->track != TRACK_BIT_NONE);
2942 
2943  return YapfTrainCheckReverse(v);
2944 }
2945 
2952 {
2953  if (station == this->last_station_visited) this->last_station_visited = INVALID_STATION;
2954 
2955  const Station *st = Station::Get(station);
2956  if (!(st->facilities & FACIL_TRAIN)) {
2957  /* The destination station has no trainstation tiles. */
2958  this->IncrementRealOrderIndex();
2959  return 0;
2960  }
2961 
2962  return st->xy;
2963 }
2964 
2967 {
2968  Train *v = this;
2969  do {
2970  v->colourmap = PAL_NONE;
2971  v->UpdateViewport(true, false);
2972  } while ((v = v->Next()) != nullptr);
2973 
2974  /* need to update acceleration and cached values since the goods on the train changed. */
2975  this->CargoChanged();
2976  this->UpdateAcceleration();
2977 }
2978 
2987 {
2989  default: NOT_REACHED();
2990  case AM_ORIGINAL:
2991  return this->DoUpdateSpeed(this->acceleration * (this->GetAccelerationStatus() == AS_BRAKE ? -4 : 2), 0, this->GetCurrentMaxSpeed());
2992 
2993  case AM_REALISTIC:
2994  return this->DoUpdateSpeed(this->GetAcceleration(), this->GetAccelerationStatus() == AS_BRAKE ? 0 : 2, this->GetCurrentMaxSpeed());
2995  }
2996 }
2997 
3003 static void TrainEnterStation(Train *v, StationID station)
3004 {
3005  v->last_station_visited = station;
3006 
3007  /* check if a train ever visited this station before */
3008  Station *st = Station::Get(station);
3009  if (!(st->had_vehicle_of_type & HVOT_TRAIN)) {
3010  st->had_vehicle_of_type |= HVOT_TRAIN;
3011  SetDParam(0, st->index);
3013  STR_NEWS_FIRST_TRAIN_ARRIVAL,
3015  v->index,
3016  st->index
3017  );
3018  AI::NewEvent(v->owner, new ScriptEventStationFirstVehicle(st->index, v->index));
3019  Game::NewEvent(new ScriptEventStationFirstVehicle(st->index, v->index));
3020  }
3021 
3022  v->force_proceed = TFP_NONE;
3024 
3025  v->BeginLoading();
3026 
3028  TriggerStationAnimation(st, v->tile, SAT_TRAIN_ARRIVES);
3029 }
3030 
3031 /* Check if the vehicle is compatible with the specified tile */
3032 static inline bool CheckCompatibleRail(const Train *v, TileIndex tile)
3033 {
3034  return IsTileOwner(tile, v->owner) &&
3035  (!v->IsFrontEngine() || HasBit(v->compatible_railtypes, GetRailType(tile)));
3036 }
3037 
3040  uint8_t small_turn;
3041  uint8_t large_turn;
3042  uint8_t z_up;
3043  uint8_t z_down;
3044 };
3045 
3048  /* normal accel */
3049  {256 / 4, 256 / 2, 256 / 4, 2},
3050  {256 / 4, 256 / 2, 256 / 4, 2},
3051  {0, 256 / 2, 256 / 4, 2},
3052 };
3053 
3059 static inline void AffectSpeedByZChange(Train *v, int old_z)
3060 {
3061  if (old_z == v->z_pos || _settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) return;
3062 
3064 
3065  if (old_z < v->z_pos) {
3066  v->cur_speed -= (v->cur_speed * asp->z_up >> 8);
3067  } else {
3068  uint16_t spd = v->cur_speed + asp->z_down;
3069  if (spd <= v->gcache.cached_max_track_speed) v->cur_speed = spd;
3070  }
3071 }
3072 
3073 static bool TrainMovedChangeSignals(TileIndex tile, DiagDirection dir)
3074 {
3075  if (IsTileType(tile, MP_RAILWAY) &&
3078  Trackdir trackdir = FindFirstTrackdir(tracks);
3079  if (UpdateSignalsOnSegment(tile, TrackdirToExitdir(trackdir), GetTileOwner(tile)) == SIGSEG_PBS && HasSignalOnTrackdir(tile, trackdir)) {
3080  /* A PBS block with a non-PBS signal facing us? */
3081  if (!IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) return true;
3082  }
3083  }
3084  return false;
3085 }
3086 
3089 {
3090  for (const Train *u = this; u != nullptr; u = u->Next()) {
3091  switch (u->track) {
3092  case TRACK_BIT_WORMHOLE:
3094  break;
3095  case TRACK_BIT_DEPOT:
3096  break;
3097  default:
3098  TryReserveRailTrack(u->tile, TrackBitsToTrack(u->track));
3099  break;
3100  }
3101  }
3102 }
3103 
3110 uint Train::Crash(bool flooded)
3111 {
3112  uint victims = 0;
3113  if (this->IsFrontEngine()) {
3114  victims += 2; // driver
3115 
3116  /* Remove the reserved path in front of the train if it is not stuck.
3117  * Also clear all reserved tracks the train is currently on. */
3118  if (!HasBit(this->flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(this);
3119  for (const Train *v = this; v != nullptr; v = v->Next()) {
3121  if (IsTileType(v->tile, MP_TUNNELBRIDGE)) {
3122  /* ClearPathReservation will not free the wormhole exit
3123  * if the train has just entered the wormhole. */
3125  }
3126  }
3127 
3128  /* we may need to update crossing we were approaching,
3129  * but must be updated after the train has been marked crashed */
3130  TileIndex crossing = TrainApproachingCrossingTile(this);
3131  if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing);
3132 
3133  /* Remove the loading indicators (if any) */
3135  }
3136 
3137  victims += this->GroundVehicleBase::Crash(flooded);
3138 
3139  this->crash_anim_pos = flooded ? 4000 : 1; // max 4440, disappear pretty fast when flooded
3140  return victims;
3141 }
3142 
3149 static uint TrainCrashed(Train *v)
3150 {
3151  uint victims = 0;
3152 
3153  /* do not crash train twice */
3154  if (!(v->vehstatus & VS_CRASHED)) {
3155  victims = v->Crash();
3156  AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_TRAIN, victims));
3157  Game::NewEvent(new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_TRAIN, victims));
3158  }
3159 
3160  /* Try to re-reserve track under already crashed train too.
3161  * Crash() clears the reservation! */
3163 
3164  return victims;
3165 }
3166 
3170  uint num;
3171 };
3172 
3179 static Vehicle *FindTrainCollideEnum(Vehicle *v, void *data)
3180 {
3182 
3183  /* not a train or in depot */
3184  if (v->type != VEH_TRAIN || Train::From(v)->track == TRACK_BIT_DEPOT) return nullptr;
3185 
3186  /* do not crash into trains of another company. */
3187  if (v->owner != tcc->v->owner) return nullptr;
3188 
3189  /* get first vehicle now to make most usual checks faster */
3190  Train *coll = Train::From(v)->First();
3191 
3192  /* can't collide with own wagons */
3193  if (coll == tcc->v) return nullptr;
3194 
3195  int x_diff = v->x_pos - tcc->v->x_pos;
3196  int y_diff = v->y_pos - tcc->v->y_pos;
3197 
3198  /* Do fast calculation to check whether trains are not in close vicinity
3199  * and quickly reject trains distant enough for any collision.
3200  * Differences are shifted by 7, mapping range [-7 .. 8] into [0 .. 15]
3201  * Differences are then ORed and then we check for any higher bits */
3202  uint hash = (y_diff + 7) | (x_diff + 7);
3203  if (hash & ~15) return nullptr;
3204 
3205  /* Slower check using multiplication */
3206  int min_diff = (Train::From(v)->gcache.cached_veh_length + 1) / 2 + (tcc->v->gcache.cached_veh_length + 1) / 2 - 1;
3207  if (x_diff * x_diff + y_diff * y_diff > min_diff * min_diff) return nullptr;
3208 
3209  /* Happens when there is a train under bridge next to bridge head */
3210  if (abs(v->z_pos - tcc->v->z_pos) > 5) return nullptr;
3211 
3212  /* crash both trains */
3213  tcc->num += TrainCrashed(tcc->v);
3214  tcc->num += TrainCrashed(coll);
3215 
3216  return nullptr; // continue searching
3217 }
3218 
3227 {
3228  /* can't collide in depot */
3229  if (v->track == TRACK_BIT_DEPOT) return false;
3230 
3231  assert(v->track == TRACK_BIT_WORMHOLE || TileVirtXY(v->x_pos, v->y_pos) == v->tile);
3232 
3233  TrainCollideChecker tcc;
3234  tcc.v = v;
3235  tcc.num = 0;
3236 
3237  /* find colliding vehicles */
3238  if (v->track == TRACK_BIT_WORMHOLE) {
3241  } else {
3243  }
3244 
3245  /* any dead -> no crash */
3246  if (tcc.num == 0) return false;
3247 
3248  SetDParam(0, tcc.num);
3249  AddTileNewsItem(STR_NEWS_TRAIN_CRASH, NT_ACCIDENT, v->tile);
3250 
3251  ModifyStationRatingAround(v->tile, v->owner, -160, 30);
3252  if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_13_TRAIN_COLLISION, v);
3253  return true;
3254 }
3255 
3256 static Vehicle *CheckTrainAtSignal(Vehicle *v, void *data)
3257 {
3258  if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return nullptr;
3259 
3260  Train *t = Train::From(v);
3261  DiagDirection exitdir = *(DiagDirection *)data;
3262 
3263  /* not front engine of a train, inside wormhole or depot, crashed */
3264  if (!t->IsFrontEngine() || !(t->track & TRACK_BIT_MASK)) return nullptr;
3265 
3266  if (t->cur_speed > 5 || VehicleExitDir(t->direction, t->track) != exitdir) return nullptr;
3267 
3268  return t;
3269 }
3270 
3278 bool TrainController(Train *v, Vehicle *nomove, bool reverse)
3279 {
3280  Train *first = v->First();
3281  Train *prev;
3282  bool direction_changed = false; // has direction of any part changed?
3283 
3284  /* For every vehicle after and including the given vehicle */
3285  for (prev = v->Previous(); v != nomove; prev = v, v = v->Next()) {
3286  DiagDirection enterdir = DIAGDIR_BEGIN;
3287  bool update_signals_crossing = false; // will we update signals or crossing state?
3288 
3290  if (v->track != TRACK_BIT_WORMHOLE) {
3291  /* Not inside tunnel */
3292  if (gp.old_tile == gp.new_tile) {
3293  /* Staying in the old tile */
3294  if (v->track == TRACK_BIT_DEPOT) {
3295  /* Inside depot */
3296  gp.x = v->x_pos;
3297  gp.y = v->y_pos;
3298  } else {
3299  /* Not inside depot */
3300 
3301  /* Reverse when we are at the end of the track already, do not move to the new position */
3302  if (v->IsFrontEngine() && !TrainCheckIfLineEnds(v, reverse)) return false;
3303 
3304  uint32_t r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
3305  if (HasBit(r, VETS_CANNOT_ENTER)) {
3306  goto invalid_rail;
3307  }
3308  if (HasBit(r, VETS_ENTERED_STATION)) {
3309  /* The new position is the end of the platform */
3311  }
3312  }
3313  } else {
3314  /* A new tile is about to be entered. */
3315 
3316  /* Determine what direction we're entering the new tile from */
3317  enterdir = DiagdirBetweenTiles(gp.old_tile, gp.new_tile);
3318  assert(IsValidDiagDirection(enterdir));
3319 
3320  /* Get the status of the tracks in the new tile and mask
3321  * away the bits that aren't reachable. */
3322  TrackStatus ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL, 0, ReverseDiagDir(enterdir));
3323  TrackdirBits reachable_trackdirs = DiagdirReachesTrackdirs(enterdir);
3324 
3325  TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts) & reachable_trackdirs;
3326  TrackBits red_signals = TrackdirBitsToTrackBits(TrackStatusToRedSignals(ts) & reachable_trackdirs);
3327 
3328  TrackBits bits = TrackdirBitsToTrackBits(trackdirbits);
3329  if (Rail90DegTurnDisallowed(GetTileRailType(gp.old_tile), GetTileRailType(gp.new_tile)) && prev == nullptr) {
3330  /* We allow wagons to make 90 deg turns, because forbid_90_deg
3331  * can be switched on halfway a turn */
3332  bits &= ~TrackCrossesTracks(FindFirstTrack(v->track));
3333  }
3334 
3335  if (bits == TRACK_BIT_NONE) goto invalid_rail;
3336 
3337  /* Check if the new tile constrains tracks that are compatible
3338  * with the current train, if not, bail out. */
3339  if (!CheckCompatibleRail(v, gp.new_tile)) goto invalid_rail;
3340 
3341  TrackBits chosen_track;
3342  if (prev == nullptr) {
3343  /* Currently the locomotive is active. Determine which one of the
3344  * available tracks to choose */
3345  chosen_track = TrackToTrackBits(ChooseTrainTrack(v, gp.new_tile, enterdir, bits, false, nullptr, true));
3346  assert(chosen_track & (bits | GetReservedTrackbits(gp.new_tile)));
3347 
3348  if (v->force_proceed != TFP_NONE && IsPlainRailTile(gp.new_tile) && HasSignals(gp.new_tile)) {
3349  /* For each signal we find decrease the counter by one.
3350  * We start at two, so the first signal we pass decreases
3351  * this to one, then if we reach the next signal it is
3352  * decreased to zero and we won't pass that new signal. */
3353  Trackdir dir = FindFirstTrackdir(trackdirbits);
3354  if (HasSignalOnTrackdir(gp.new_tile, dir) ||
3356  GetSignalType(gp.new_tile, TrackdirToTrack(dir)) != SIGTYPE_PBS)) {
3357  /* However, we do not want to be stopped by PBS signals
3358  * entered via the back. */
3359  v->force_proceed = (v->force_proceed == TFP_SIGNAL) ? TFP_STUCK : TFP_NONE;
3361  }
3362  }
3363 
3364  /* Check if it's a red signal and that force proceed is not clicked. */
3365  if ((red_signals & chosen_track) && v->force_proceed == TFP_NONE) {
3366  /* In front of a red signal */
3367  Trackdir i = FindFirstTrackdir(trackdirbits);
3368 
3369  /* Don't handle stuck trains here. */
3370  if (HasBit(v->flags, VRF_TRAIN_STUCK)) return false;
3371 
3373  v->cur_speed = 0;
3374  v->subspeed = 0;
3375  v->progress = 255; // make sure that every bit of acceleration will hit the signal again, so speed stays 0.
3377  } else if (HasSignalOnTrackdir(gp.new_tile, i)) {
3378  v->cur_speed = 0;
3379  v->subspeed = 0;
3380  v->progress = 255; // make sure that every bit of acceleration will hit the signal again, so speed stays 0.
3382  DiagDirection exitdir = TrackdirToExitdir(i);
3383  TileIndex o_tile = TileAddByDiagDir(gp.new_tile, exitdir);
3384 
3385  exitdir = ReverseDiagDir(exitdir);
3386 
3387  /* check if a train is waiting on the other side */
3388  if (!HasVehicleOnPos(o_tile, &exitdir, &CheckTrainAtSignal)) return false;
3389  }
3390  }
3391 
3392  /* If we would reverse but are currently in a PBS block and
3393  * reversing of stuck trains is disabled, don't reverse.
3394  * This does not apply if the reason for reversing is a one-way
3395  * signal blocking us, because a train would then be stuck forever. */
3397  UpdateSignalsOnSegment(v->tile, enterdir, v->owner) == SIGSEG_PBS) {
3398  v->wait_counter = 0;
3399  return false;
3400  }
3401  goto reverse_train_direction;
3402  } else {
3403  TryReserveRailTrack(gp.new_tile, TrackBitsToTrack(chosen_track), false);
3404  }
3405  } else {
3406  /* The wagon is active, simply follow the prev vehicle. */
3407  if (prev->tile == gp.new_tile) {
3408  /* Choose the same track as prev */
3409  if (prev->track == TRACK_BIT_WORMHOLE) {
3410  /* Vehicles entering tunnels enter the wormhole earlier than for bridges.
3411  * However, just choose the track into the wormhole. */
3412  assert(IsTunnel(prev->tile));
3413  chosen_track = bits;
3414  } else {
3415  chosen_track = prev->track;
3416  }
3417  } else {
3418  /* Choose the track that leads to the tile where prev is.
3419  * This case is active if 'prev' is already on the second next tile, when 'v' just enters the next tile.
3420  * I.e. when the tile between them has only space for a single vehicle like
3421  * 1) horizontal/vertical track tiles and
3422  * 2) some orientations of tunnel entries, where the vehicle is already inside the wormhole at 8/16 from the tile edge.
3423  * Is also the train just reversing, the wagon inside the tunnel is 'on' the tile of the opposite tunnel entry.
3424  */
3425  static const TrackBits _connecting_track[DIAGDIR_END][DIAGDIR_END] = {
3430  };
3431  DiagDirection exitdir = DiagdirBetweenTiles(gp.new_tile, prev->tile);
3432  assert(IsValidDiagDirection(exitdir));
3433  chosen_track = _connecting_track[enterdir][exitdir];
3434  }
3435  chosen_track &= bits;
3436  }
3437 
3438  /* Make sure chosen track is a valid track */
3439  assert(
3440  chosen_track == TRACK_BIT_X || chosen_track == TRACK_BIT_Y ||
3441  chosen_track == TRACK_BIT_UPPER || chosen_track == TRACK_BIT_LOWER ||
3442  chosen_track == TRACK_BIT_LEFT || chosen_track == TRACK_BIT_RIGHT);
3443 
3444  /* Update XY to reflect the entrance to the new tile, and select the direction to use */
3445  const uint8_t *b = _initial_tile_subcoord[FindFirstBit(chosen_track)][enterdir];
3446  gp.x = (gp.x & ~0xF) | b[0];
3447  gp.y = (gp.y & ~0xF) | b[1];
3448  Direction chosen_dir = (Direction)b[2];
3449 
3450  /* Call the landscape function and tell it that the vehicle entered the tile */
3451  uint32_t r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
3452  if (HasBit(r, VETS_CANNOT_ENTER)) {
3453  goto invalid_rail;
3454  }
3455 
3456  if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
3457  Track track = FindFirstTrack(chosen_track);
3458  Trackdir tdir = TrackDirectionToTrackdir(track, chosen_dir);
3459  if (v->IsFrontEngine() && HasPbsSignalOnTrackdir(gp.new_tile, tdir)) {
3462  }
3463 
3464  /* Clear any track reservation when the last vehicle leaves the tile */
3465  if (v->Next() == nullptr) ClearPathReservation(v, v->tile, v->GetVehicleTrackdir());
3466 
3467  v->tile = gp.new_tile;
3468 
3470  v->First()->ConsistChanged(CCF_TRACK);
3471  }
3472 
3473  v->track = chosen_track;
3474  assert(v->track);
3475  }
3476 
3477  /* We need to update signal status, but after the vehicle position hash
3478  * has been updated by UpdateInclination() */
3479  update_signals_crossing = true;
3480 
3481  if (chosen_dir != v->direction) {
3482  if (prev == nullptr && _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) {
3484  DirDiff diff = DirDifference(v->direction, chosen_dir);
3485  v->cur_speed -= (diff == DIRDIFF_45RIGHT || diff == DIRDIFF_45LEFT ? asp->small_turn : asp->large_turn) * v->cur_speed >> 8;
3486  }
3487  direction_changed = true;
3488  v->direction = chosen_dir;
3489  }
3490 
3491  if (v->IsFrontEngine()) {
3492  v->wait_counter = 0;
3493 
3494  /* If we are approaching a crossing that is reserved, play the sound now. */
3496  if (crossing != INVALID_TILE && HasCrossingReservation(crossing) && _settings_client.sound.ambient) SndPlayTileFx(SND_0E_LEVEL_CROSSING, crossing);
3497 
3498  /* Always try to extend the reservation when entering a tile. */
3499  CheckNextTrainTile(v);
3500  }
3501 
3502  if (HasBit(r, VETS_ENTERED_STATION)) {
3503  /* The new position is the location where we want to stop */
3505  }
3506  }
3507  } else {
3509  /* Perform look-ahead on tunnel exit. */
3510  if (v->IsFrontEngine()) {
3512  CheckNextTrainTile(v);
3513  }
3514  /* Prevent v->UpdateInclination() being called with wrong parameters.
3515  * This could happen if the train was reversed inside the tunnel/bridge. */
3516  if (gp.old_tile == gp.new_tile) {
3518  }
3519  } else {
3520  v->x_pos = gp.x;
3521  v->y_pos = gp.y;
3522  v->UpdatePosition();
3523  if ((v->vehstatus & VS_HIDDEN) == 0) v->Vehicle::UpdateViewport(true);
3524  continue;
3525  }
3526  }
3527 
3528  /* update image of train, as well as delta XY */
3529  v->UpdateDeltaXY();
3530 
3531  v->x_pos = gp.x;
3532  v->y_pos = gp.y;
3533  v->UpdatePosition();
3534 
3535  /* update the Z position of the vehicle */
3536  int old_z = v->UpdateInclination(gp.new_tile != gp.old_tile, false);
3537 
3538  if (prev == nullptr) {
3539  /* This is the first vehicle in the train */
3540  AffectSpeedByZChange(v, old_z);
3541  }
3542 
3543  if (update_signals_crossing) {
3544  if (v->IsFrontEngine()) {
3545  if (TrainMovedChangeSignals(gp.new_tile, enterdir)) {
3546  /* We are entering a block with PBS signals right now, but
3547  * not through a PBS signal. This means we don't have a
3548  * reservation right now. As a conventional signal will only
3549  * ever be green if no other train is in the block, getting
3550  * a path should always be possible. If the player built
3551  * such a strange network that it is not possible, the train
3552  * will be marked as stuck and the player has to deal with
3553  * the problem. */
3554  if ((!HasReservedTracks(gp.new_tile, v->track) &&
3555  !TryReserveRailTrack(gp.new_tile, FindFirstTrack(v->track))) ||
3556  !TryPathReserve(v)) {
3557  MarkTrainAsStuck(v);
3558  }
3559  }
3560  }
3561 
3562  /* Signals can only change when the first
3563  * (above) or the last vehicle moves. */
3564  if (v->Next() == nullptr) {
3565  TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir));
3567  }
3568  }
3569 
3570  /* Do not check on every tick to save some computing time. */
3572  }
3573 
3574  if (direction_changed) first->tcache.cached_max_curve_speed = first->GetCurveSpeedLimit();
3575 
3576  return true;
3577 
3578 invalid_rail:
3579  /* We've reached end of line?? */
3580  if (prev != nullptr) FatalError("Disconnecting train");
3581 
3582 reverse_train_direction:
3583  if (reverse) {
3584  v->wait_counter = 0;
3585  v->cur_speed = 0;
3586  v->subspeed = 0;
3588  }
3589 
3590  return false;
3591 }
3592 
3600 {
3601  TrackBits *trackbits = (TrackBits *)data;
3602 
3603  if (v->type == VEH_TRAIN && (v->vehstatus & VS_CRASHED) != 0) {
3604  TrackBits train_tbits = Train::From(v)->track;
3605  if (train_tbits == TRACK_BIT_WORMHOLE) {
3606  /* Vehicle is inside a wormhole, v->track contains no useful value then. */
3608  } else if (train_tbits != TRACK_BIT_DEPOT) {
3609  *trackbits |= train_tbits;
3610  }
3611  }
3612 
3613  return nullptr;
3614 }
3615 
3616 static bool IsRailStationPlatformOccupied(TileIndex tile)
3617 {
3619 
3620  for (TileIndex t = tile; IsCompatibleTrainStationTile(t, tile); t -= delta) {
3621  if (HasVehicleOnPos(t, nullptr, &TrainOnTileEnum)) return true;
3622  }
3623  for (TileIndex t = tile + delta; IsCompatibleTrainStationTile(t, tile); t += delta) {
3624  if (HasVehicleOnPos(t, nullptr, &TrainOnTileEnum)) return true;
3625  }
3626 
3627  return false;
3628 }
3629 
3637 static void DeleteLastWagon(Train *v)
3638 {
3639  Train *first = v->First();
3640 
3641  /* Go to the last wagon and delete the link pointing there
3642  * *u is then the one-before-last wagon, and *v the last
3643  * one which will physically be removed */
3644  Train *u = v;
3645  for (; v->Next() != nullptr; v = v->Next()) u = v;
3646  u->SetNext(nullptr);
3647 
3648  if (first != v) {
3649  /* Recalculate cached train properties */
3650  first->ConsistChanged(CCF_ARRANGE);
3651  /* Update the depot window if the first vehicle is in depot -
3652  * if v == first, then it is updated in PreDestructor() */
3653  if (first->track == TRACK_BIT_DEPOT) {
3655  }
3656  v->last_station_visited = first->last_station_visited; // for PreDestructor
3657  }
3658 
3659  /* 'v' shouldn't be accessed after it has been deleted */
3660  TrackBits trackbits = v->track;
3661  TileIndex tile = v->tile;
3662  Owner owner = v->owner;
3663 
3664  delete v;
3665  v = nullptr; // make sure nobody will try to read 'v' anymore
3666 
3667  if (trackbits == TRACK_BIT_WORMHOLE) {
3668  /* Vehicle is inside a wormhole, v->track contains no useful value then. */
3670  }
3671 
3672  Track track = TrackBitsToTrack(trackbits);
3673  if (HasReservedTracks(tile, trackbits)) {
3674  UnreserveRailTrack(tile, track);
3675 
3676  /* If there are still crashed vehicles on the tile, give the track reservation to them */
3677  TrackBits remaining_trackbits = TRACK_BIT_NONE;
3678  FindVehicleOnPos(tile, &remaining_trackbits, CollectTrackbitsFromCrashedVehiclesEnum);
3679 
3680  /* It is important that these two are the first in the loop, as reservation cannot deal with every trackbit combination */
3681  assert(TRACK_BEGIN == TRACK_X && TRACK_Y == TRACK_BEGIN + 1);
3682  for (Track t : SetTrackBitIterator(remaining_trackbits)) TryReserveRailTrack(tile, t);
3683  }
3684 
3685  /* check if the wagon was on a road/rail-crossing */
3686  if (IsLevelCrossingTile(tile)) UpdateLevelCrossing(tile);
3687 
3688  if (IsRailStationTile(tile)) {
3689  bool occupied = IsRailStationPlatformOccupied(tile);
3691  SetRailStationPlatformReservation(tile, dir, occupied);
3692  SetRailStationPlatformReservation(tile, ReverseDiagDir(dir), occupied);
3693  }
3694 
3695  /* Update signals */
3696  if (IsTileType(tile, MP_TUNNELBRIDGE) || IsRailDepotTile(tile)) {
3698  } else {
3699  SetSignalsOnBothDir(tile, track, owner);
3700  }
3701 }
3702 
3708 {
3709  static const DirDiff delta[] = {
3711  };
3712 
3713  do {
3714  /* We don't need to twist around vehicles if they're not visible */
3715  if (!(v->vehstatus & VS_HIDDEN)) {
3716  v->direction = ChangeDir(v->direction, delta[GB(Random(), 0, 2)]);
3717  /* Refrain from updating the z position of the vehicle when on
3718  * a bridge, because UpdateInclination() will put the vehicle under
3719  * the bridge in that case */
3720  if (v->track != TRACK_BIT_WORMHOLE) {
3721  v->UpdatePosition();
3722  v->UpdateInclination(false, true);
3723  } else {
3724  v->UpdateViewport(false, true);
3725  }
3726  }
3727  } while ((v = v->Next()) != nullptr);
3728 }
3729 
3735 static bool HandleCrashedTrain(Train *v)
3736 {
3737  int state = ++v->crash_anim_pos;
3738 
3739  if (state == 4 && !(v->vehstatus & VS_HIDDEN)) {
3741  }
3742 
3743  uint32_t r;
3744  if (state <= 200 && Chance16R(1, 7, r)) {
3745  int index = (r * 10 >> 16);
3746 
3747  Vehicle *u = v;
3748  do {
3749  if (--index < 0) {
3750  r = Random();
3751 
3753  GB(r, 8, 3) + 2,
3754  GB(r, 16, 3) + 2,
3755  GB(r, 0, 3) + 5,
3757  break;
3758  }
3759  } while ((u = u->Next()) != nullptr);
3760  }
3761 
3762  if (state <= 240 && !(v->tick_counter & 3)) ChangeTrainDirRandomly(v);
3763 
3764  if (state >= 4440 && !(v->tick_counter & 0x1F)) {
3765  bool ret = v->Next() != nullptr;
3766  DeleteLastWagon(v);
3767  return ret;
3768  }
3769 
3770  return true;
3771 }
3772 
3774 static const uint16_t _breakdown_speeds[16] = {
3775  225, 210, 195, 180, 165, 150, 135, 120, 105, 90, 75, 60, 45, 30, 15, 15
3776 };
3777 
3778 
3787 static bool TrainApproachingLineEnd(Train *v, bool signal, bool reverse)
3788 {
3789  /* Calc position within the current tile */
3790  uint x = v->x_pos & 0xF;
3791  uint y = v->y_pos & 0xF;
3792 
3793  /* for diagonal directions, 'x' will be 0..15 -
3794  * for other directions, it will be 1, 3, 5, ..., 15 */
3795  switch (v->direction) {
3796  case DIR_N : x = ~x + ~y + 25; break;
3797  case DIR_NW: x = y; [[fallthrough]];
3798  case DIR_NE: x = ~x + 16; break;
3799  case DIR_E : x = ~x + y + 9; break;
3800  case DIR_SE: x = y; break;
3801  case DIR_S : x = x + y - 7; break;
3802  case DIR_W : x = ~y + x + 9; break;
3803  default: break;
3804  }
3805 
3806  /* Do not reverse when approaching red signal. Make sure the vehicle's front
3807  * does not cross the tile boundary when we do reverse, but as the vehicle's
3808  * location is based on their center, use half a vehicle's length as offset.
3809  * Multiply the half-length by two for straight directions to compensate that
3810  * we only get odd x offsets there. */
3811  if (!signal && x + (v->gcache.cached_veh_length + 1) / 2 * (IsDiagonalDirection(v->direction) ? 1 : 2) >= TILE_SIZE) {
3812  /* we are too near the tile end, reverse now */
3813  v->cur_speed = 0;
3814  if (reverse) ReverseTrainDirection(v);
3815  return false;
3816  }
3817 
3818  /* slow down */
3820  uint16_t break_speed = _breakdown_speeds[x & 0xF];
3821  if (break_speed < v->cur_speed) v->cur_speed = break_speed;
3822 
3823  return true;
3824 }
3825 
3826 
3832 static bool TrainCanLeaveTile(const Train *v)
3833 {
3834  /* Exit if inside a tunnel/bridge or a depot */
3835  if (v->track == TRACK_BIT_WORMHOLE || v->track == TRACK_BIT_DEPOT) return false;
3836 
3837  TileIndex tile = v->tile;
3838 
3839  /* entering a tunnel/bridge? */
3840  if (IsTileType(tile, MP_TUNNELBRIDGE)) {
3842  if (DiagDirToDir(dir) == v->direction) return false;
3843  }
3844 
3845  /* entering a depot? */
3846  if (IsRailDepotTile(tile)) {
3848  if (DiagDirToDir(dir) == v->direction) return false;
3849  }
3850 
3851  return true;
3852 }
3853 
3854 
3863 {
3864  assert(v->IsFrontEngine());
3865  assert(!(v->vehstatus & VS_CRASHED));
3866 
3867  if (!TrainCanLeaveTile(v)) return INVALID_TILE;
3868 
3869  DiagDirection dir = VehicleExitDir(v->direction, v->track);
3870  TileIndex tile = v->tile + TileOffsByDiagDir(dir);
3871 
3872  /* not a crossing || wrong axis || unusable rail (wrong type or owner) */
3873  if (!IsLevelCrossingTile(tile) || DiagDirToAxis(dir) == GetCrossingRoadAxis(tile) ||
3874  !CheckCompatibleRail(v, tile)) {
3875  return INVALID_TILE;
3876  }
3877 
3878  return tile;
3879 }
3880 
3881 
3889 static bool TrainCheckIfLineEnds(Train *v, bool reverse)
3890 {
3891  /* First, handle broken down train */
3892 
3893  int t = v->breakdown_ctr;
3894  if (t > 1) {
3896 
3897  uint16_t break_speed = _breakdown_speeds[GB(~t, 4, 4)];
3898  if (break_speed < v->cur_speed) v->cur_speed = break_speed;
3899  } else {
3900  v->vehstatus &= ~VS_TRAIN_SLOWING;
3901  }
3902 
3903  if (!TrainCanLeaveTile(v)) return true;
3904 
3905  /* Determine the non-diagonal direction in which we will exit this tile */
3906  DiagDirection dir = VehicleExitDir(v->direction, v->track);
3907  /* Calculate next tile */
3908  TileIndex tile = v->tile + TileOffsByDiagDir(dir);
3909 
3910  /* Determine the track status on the next tile */
3911  TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_RAIL, 0, ReverseDiagDir(dir));
3912  TrackdirBits reachable_trackdirs = DiagdirReachesTrackdirs(dir);
3913 
3914  TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts) & reachable_trackdirs;
3915  TrackdirBits red_signals = TrackStatusToRedSignals(ts) & reachable_trackdirs;
3916 
3917  /* We are sure the train is not entering a depot, it is detected above */
3918 
3919  /* mask unreachable track bits if we are forbidden to do 90deg turns */
3920  TrackBits bits = TrackdirBitsToTrackBits(trackdirbits);
3922  bits &= ~TrackCrossesTracks(FindFirstTrack(v->track));
3923  }
3924 
3925  /* no suitable trackbits at all || unusable rail (wrong type or owner) */
3926  if (bits == TRACK_BIT_NONE || !CheckCompatibleRail(v, tile)) {
3927  return TrainApproachingLineEnd(v, false, reverse);
3928  }
3929 
3930  /* approaching red signal */
3931  if ((trackdirbits & red_signals) != 0) return TrainApproachingLineEnd(v, true, reverse);
3932 
3933  /* approaching a rail/road crossing? then make it red */
3935 
3936  return true;
3937 }
3938 
3939 
3940 static bool TrainLocoHandler(Train *v, bool mode)
3941 {
3942  /* train has crashed? */
3943  if (v->vehstatus & VS_CRASHED) {
3944  return mode ? true : HandleCrashedTrain(v); // 'this' can be deleted here
3945  }
3946 
3947  if (v->force_proceed != TFP_NONE) {
3948  ClrBit(v->flags, VRF_TRAIN_STUCK);
3950  }
3951 
3952  /* train is broken down? */
3953  if (v->HandleBreakdown()) return true;
3954 
3955  if (HasBit(v->flags, VRF_REVERSING) && v->cur_speed == 0) {
3957  }
3958 
3959  /* exit if train is stopped */
3960  if ((v->vehstatus & VS_STOPPED) && v->cur_speed == 0) return true;
3961 
3962  bool valid_order = !v->current_order.IsType(OT_NOTHING) && v->current_order.GetType() != OT_CONDITIONAL;
3963  if (ProcessOrders(v) && CheckReverseTrain(v)) {
3964  v->wait_counter = 0;
3965  v->cur_speed = 0;
3966  v->subspeed = 0;
3967  ClrBit(v->flags, VRF_LEAVING_STATION);
3969  return true;
3970  } else if (HasBit(v->flags, VRF_LEAVING_STATION)) {
3971  /* Try to reserve a path when leaving the station as we
3972  * might not be marked as wanting a reservation, e.g.
3973  * when an overlength train gets turned around in a station. */
3974  DiagDirection dir = VehicleExitDir(v->direction, v->track);
3976 
3978  TryPathReserve(v, true, true);
3979  }
3980  ClrBit(v->flags, VRF_LEAVING_STATION);
3981  }
3982 
3983  v->HandleLoading(mode);
3984 
3985  if (v->current_order.IsType(OT_LOADING)) return true;
3986 
3987  if (CheckTrainStayInDepot(v)) return true;
3988 
3989  if (!mode) v->ShowVisualEffect();
3990 
3991  /* We had no order but have an order now, do look ahead. */
3992  if (!valid_order && !v->current_order.IsType(OT_NOTHING)) {
3993  CheckNextTrainTile(v);
3994  }
3995 
3996  /* Handle stuck trains. */
3997  if (!mode && HasBit(v->flags, VRF_TRAIN_STUCK)) {
3998  ++v->wait_counter;
3999 
4000  /* Should we try reversing this tick if still stuck? */
4002 
4003  if (!turn_around && v->wait_counter % _settings_game.pf.path_backoff_interval != 0 && v->force_proceed == TFP_NONE) return true;
4004  if (!TryPathReserve(v)) {
4005  /* Still stuck. */
4006  if (turn_around) ReverseTrainDirection(v);
4007 
4009  /* Show message to player. */
4011  SetDParam(0, v->index);
4012  AddVehicleAdviceNewsItem(STR_NEWS_TRAIN_IS_STUCK, v->index);
4013  }
4014  v->wait_counter = 0;
4015  }
4016  /* Exit if force proceed not pressed, else reset stuck flag anyway. */
4017  if (v->force_proceed == TFP_NONE) return true;
4018  ClrBit(v->flags, VRF_TRAIN_STUCK);
4019  v->wait_counter = 0;
4021  }
4022  }
4023 
4024  if (v->current_order.IsType(OT_LEAVESTATION)) {
4025  v->current_order.Free();
4027  return true;
4028  }
4029 
4030  int j = v->UpdateSpeed();
4031 
4032  /* we need to invalidate the widget if we are stopping from 'Stopping 0 km/h' to 'Stopped' */
4033  if (v->cur_speed == 0 && (v->vehstatus & VS_STOPPED)) {
4034  /* If we manually stopped, we're not force-proceeding anymore. */
4035  v->force_proceed = TFP_NONE;
4037  }
4038 
4039  int adv_spd = v->GetAdvanceDistance();
4040  if (j < adv_spd) {
4041  /* if the vehicle has speed 0, update the last_speed field. */
4042  if (v->cur_speed == 0) v->SetLastSpeed();
4043  } else {
4045  /* Loop until the train has finished moving. */
4046  for (;;) {
4047  j -= adv_spd;
4048  TrainController(v, nullptr);
4049  /* Don't continue to move if the train crashed. */
4050  if (CheckTrainCollision(v)) break;
4051  /* Determine distance to next map position */
4052  adv_spd = v->GetAdvanceDistance();
4053 
4054  /* No more moving this tick */
4055  if (j < adv_spd || v->cur_speed == 0) break;
4056 
4057  OrderType order_type = v->current_order.GetType();
4058  /* Do not skip waypoints (incl. 'via' stations) when passing through at full speed. */
4059  if ((order_type == OT_GOTO_WAYPOINT || order_type == OT_GOTO_STATION) &&
4061  IsTileType(v->tile, MP_STATION) &&
4063  ProcessOrders(v);
4064  }
4065  }
4066  v->SetLastSpeed();
4067  }
4068 
4069  for (Train *u = v; u != nullptr; u = u->Next()) {
4070  if ((u->vehstatus & VS_HIDDEN) != 0) continue;
4071 
4072  u->UpdateViewport(false, false);
4073  }
4074 
4075  if (v->progress == 0) v->progress = j; // Save unused spd for next time, if TrainController didn't set progress
4076 
4077  return true;
4078 }
4079 
4085 {
4086  Money cost = 0;
4087  const Train *v = this;
4088 
4089  do {
4090  const Engine *e = v->GetEngine();
4091  if (e->u.rail.running_cost_class == INVALID_PRICE) continue;
4092 
4093  uint cost_factor = GetVehicleProperty(v, PROP_TRAIN_RUNNING_COST_FACTOR, e->u.rail.running_cost);
4094  if (cost_factor == 0) continue;
4095 
4096  /* Halve running cost for multiheaded parts */
4097  if (v->IsMultiheaded()) cost_factor /= 2;
4098 
4099  cost += GetPrice(e->u.rail.running_cost_class, cost_factor, e->GetGRF());
4100  } while ((v = v->GetNextVehicle()) != nullptr);
4101 
4102  return cost;
4103 }
4104 
4110 {
4111  this->tick_counter++;
4112 
4113  if (this->IsFrontEngine()) {
4115 
4116  if (!(this->vehstatus & VS_STOPPED) || this->cur_speed > 0) this->running_ticks++;
4117 
4118  this->current_order_time++;
4119 
4120  if (!TrainLocoHandler(this, false)) return false;
4121 
4122  return TrainLocoHandler(this, true);
4123  } else if (this->IsFreeWagon() && (this->vehstatus & VS_CRASHED)) {
4124  /* Delete flooded standalone wagon chain */
4125  if (++this->crash_anim_pos >= 4400) {
4126  delete this;
4127  return false;
4128  }
4129  }
4130 
4131  return true;
4132 }
4133 
4139 {
4140  if (Company::Get(v->owner)->settings.vehicle.servint_trains == 0 || !v->NeedsAutomaticServicing()) return;
4141  if (v->IsChainInDepot()) {
4143  return;
4144  }
4145 
4147 
4148  FindDepotData tfdd = FindClosestTrainDepot(v, max_penalty);
4149  /* Only go to the depot if it is not too far out of our way. */
4150  if (tfdd.best_length == UINT_MAX || tfdd.best_length > max_penalty) {
4151  if (v->current_order.IsType(OT_GOTO_DEPOT)) {
4152  /* If we were already heading for a depot but it has
4153  * suddenly moved farther away, we continue our normal
4154  * schedule? */
4155  v->current_order.MakeDummy();
4157  }
4158  return;
4159  }
4160 
4161  DepotID depot = GetDepotIndex(tfdd.tile);
4162 
4163  if (v->current_order.IsType(OT_GOTO_DEPOT) &&
4164  v->current_order.GetDestination() != depot &&
4165  !Chance16(3, 16)) {
4166  return;
4167  }
4168 
4171  v->dest_tile = tfdd.tile;
4173 }
4174 
4177 {
4178  AgeVehicle(this);
4179 }
4180 
4183 {
4184  EconomyAgeVehicle(this);
4185 
4186  if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
4187 
4188  if (this->IsFrontEngine()) {
4189  CheckVehicleBreakdown(this);
4190 
4192 
4193  CheckOrders(this);
4194 
4195  /* update destination */
4196  if (this->current_order.IsType(OT_GOTO_STATION)) {
4198  if (tile != INVALID_TILE) this->dest_tile = tile;
4199  }
4200 
4201  if (this->running_ticks != 0) {
4202  /* running costs */
4204 
4205  this->profit_this_year -= cost.GetCost();
4206  this->running_ticks = 0;
4207 
4208  SubtractMoneyFromCompanyFract(this->owner, cost);
4209 
4212  }
4213  }
4214 }
4215 
4221 {
4222  if (this->vehstatus & VS_CRASHED) return INVALID_TRACKDIR;
4223 
4224  if (this->track == TRACK_BIT_DEPOT) {
4225  /* We'll assume the train is facing outwards */
4226  return DiagDirToDiagTrackdir(GetRailDepotDirection(this->tile)); // Train in depot
4227  }
4228 
4229  if (this->track == TRACK_BIT_WORMHOLE) {
4230  /* train in tunnel or on bridge, so just use its direction and assume a diagonal track */
4231  return DiagDirToDiagTrackdir(DirToDiagDir(this->direction));
4232  }
4233 
4234  return TrackDirectionToTrackdir(FindFirstTrack(this->track), this->direction);
4235 }
4236 
4237 uint16_t Train::GetMaxWeight() const
4238 {
4239  uint16_t weight = CargoSpec::Get(this->cargo_type)->WeightOfNUnitsInTrain(this->GetEngine()->DetermineCapacity(this));
4240 
4241  /* Vehicle weight is not added for articulated parts. */
4242  if (!this->IsArticulatedPart()) {
4243  weight += GetVehicleProperty(this, PROP_TRAIN_WEIGHT, RailVehInfo(this->engine_type)->weight);
4244  }
4245 
4246  /* Powered wagons have extra weight added. */
4247  if (HasBit(this->flags, VRF_POWEREDWAGON)) {
4248  weight += RailVehInfo(this->gcache.first_engine)->pow_wag_weight;
4249  }
4250 
4251  return weight;
4252 }
Base functions for all AIs.
void AddArticulatedParts(Vehicle *first)
Add the remaining articulated parts to the given vehicle.
void CheckConsistencyOfArticulatedVehicle(const Vehicle *v)
Checks whether the specs of freshly build articulated vehicles are consistent with the information sp...
Functions related to articulated vehicles.
void CheckCargoCapacity(Vehicle *v)
Check the capacity of all vehicles in a chain and spread cargo if needed.
constexpr debug_inline bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T AssignBit(T &x, const uint8_t y, bool value)
Assigns a bit in a variable.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr uint8_t FindFirstBit(T x)
Search the first set bit in a value.
constexpr static debug_inline uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr T ToggleBit(T &x, const uint8_t y)
Toggles a bit in a variable.
constexpr T KillFirstBit(T value)
Clear the first bit in an integer.
constexpr T ClrBit(T &x, const uint8_t y)
Clears a bit in a variable.
const BridgeSpec * GetBridgeSpec(BridgeType i)
Get the specification of a bridge type.
Definition: bridge.h:66
bool IsBridgeTile(Tile t)
checks if there is a bridge on this tile
Definition: bridge_map.h:35
BridgeType GetBridgeType(Tile t)
Determines the type of bridge on a tile.
Definition: bridge_map.h:56
bool IsBridge(Tile t)
Checks if this is a bridge, instead of a tunnel.
Definition: bridge_map.h:24
uint8_t CargoID
Cargo slots to indicate a cargo type within a game.
Definition: cargo_type.h:22
bool IsValidCargoID(CargoID t)
Test whether cargo type is not INVALID_CARGO.
Definition: cargo_type.h:107
static void NewEvent(CompanyID company, ScriptEvent *event)
Queue a new event for an AI.
Definition: ai_core.cpp:243
Common return value for all commands.
Definition: command_type.h:23
void AddCost(const Money &cost)
Adds the given cost to the cost of the command.
Definition: command_type.h:63
Money GetCost() const
The costs as made up to this moment.
Definition: command_type.h:83
bool Failed() const
Did this command fail?
Definition: command_type.h:171
static void NewEvent(class ScriptEvent *event)
Queue a new event for a Game Script.
Definition: game_core.cpp:146
RAII class for measuring multi-step elements of performance.
This struct contains all the info that is needed to draw and construct tracks.
Definition: rail.h:127
RailTypes powered_railtypes
bitmask to the OTHER railtypes on which an engine of THIS railtype generates power
Definition: rail.h:188
RailTypes compatible_railtypes
bitmask to the OTHER railtypes on which an engine of THIS railtype can physically travel
Definition: rail.h:191
uint8_t curve_speed
Multiplier for curve maximum speed advantage.
Definition: rail.h:206
uint8_t acceleration_type
Acceleration type of this rail type.
Definition: rail.h:226
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
static Date date
Current date in days (day counter).
static Year year
Current year, starting at 0.
static constexpr int DAYS_IN_YEAR
days per year
static Date date
Current date in days (day counter).
uint StoredCount() const
Returns sum of cargo on board the vehicle (ie not only reserved).
Definition: cargopacket.h:434
This class will save the current order of a vehicle and restore it on destruction.
Definition: train_cmd.cpp:2599
void Restore()
Restore the saved order to the vehicle.
Definition: train_cmd.cpp:2624
~VehicleOrderSaver()
Restore the saved order to the vehicle, if Restore() has not already been called.
Definition: train_cmd.cpp:2636
bool SwitchToNextOrder(bool skip_first)
Set the current vehicle order to the next order in the order list.
Definition: train_cmd.cpp:2646
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
Definition: command_func.h:28
#define return_cmd_error(errcode)
Returns from a function with a specific StringID as error.
Definition: command_func.h:38
DoCommandFlag
List of flags for a command.
Definition: command_type.h:374
@ DC_AUTOREPLACE
autoreplace/autorenew is in progress, this shall disable vehicle limits when building,...
Definition: command_type.h:383
@ DC_NO_CARGO_CAP_CHECK
when autoreplace/autorenew is in progress, this shall prevent truncating the amount of cargo in the v...
Definition: command_type.h:384
@ DC_EXEC
execute the given command
Definition: command_type.h:376
Definition of stuff that is very close to a company, like the company struct itself.
CommandCost CheckOwnership(Owner owner, TileIndex tile)
Check whether the current owner owns something.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:52
CompanyID _current_company
Company currently doing an action.
Definition: company_cmd.cpp:53
void SubtractMoneyFromCompanyFract(CompanyID company, const CommandCost &cst)
Subtract money from a company, including the money fraction.
Functions related to companies.
Owner
Enum for all companies/owners.
Definition: company_type.h:18
DepotID GetDepotIndex(Tile t)
Get the index of which depot is attached to the tile.
Definition: depot_map.h:52
uint16_t DepotID
Type for the unique identifier of depots.
Definition: depot_type.h:13
DirDiff DirDifference(Direction d0, Direction d1)
Calculate the difference between two directions.
Direction DiagDirToDir(DiagDirection dir)
Convert a DiagDirection to a Direction.
DiagDirection ReverseDiagDir(DiagDirection d)
Returns the reverse direction of the given DiagDirection.
Direction ReverseDir(Direction d)
Return the reverse of a direction.
bool IsValidDiagDirection(DiagDirection d)
Checks if an integer value is a valid DiagDirection.
Direction ChangeDir(Direction d, DirDiff delta)
Change a direction by a given difference.
DiagDirection AxisToDiagDir(Axis a)
Converts an Axis to a DiagDirection.
bool IsDiagonalDirection(Direction dir)
Checks if a given Direction is diagonal.
Axis DiagDirToAxis(DiagDirection d)
Convert a DiagDirection to the axis.
DiagDirection DirToDiagDir(Direction dir)
Convert a Direction to a DiagDirection.
Direction
Defines the 8 directions on the map.
@ DIR_SW
Southwest.
@ DIR_NW
Northwest.
@ DIR_N
North.
@ DIR_SE
Southeast.
@ DIR_S
South.
@ DIR_NE
Northeast.
@ DIR_W
West.
@ DIR_E
East.
Axis
Allow incrementing of DiagDirDiff variables.
DiagDirection
Enumeration for diagonal directions.
@ DIAGDIR_END
Used for iterations.
@ DIAGDIR_BEGIN
Used for iterations.
@ INVALID_DIAGDIR
Flag for an invalid DiagDirection.
DirDiff
Allow incrementing of Direction variables.
@ DIRDIFF_90LEFT
Angle of 90 degrees left.
@ DIRDIFF_45LEFT
Angle of 45 degrees left.
@ DIRDIFF_45RIGHT
Angle of 45 degrees right.
@ DIRDIFF_SAME
Both directions faces to the same direction.
@ DIRDIFF_90RIGHT
Angle of 90 degrees right.
Money GetPrice(Price index, uint cost_factor, const GRFFile *grf_file, int shift)
Determine a certain price.
Definition: economy.cpp:969
@ EXPENSES_TRAIN_RUN
Running costs trains.
Definition: economy_type.h:175
@ EXPENSES_NEW_VEHICLES
New vehicles.
Definition: economy_type.h:174
EffectVehicle * CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicleType type)
Create an effect vehicle above a particular vehicle.
Functions related to effect vehicles.
@ EV_EXPLOSION_SMALL
Various explosions.
@ EV_EXPLOSION_LARGE
Various explosions.
@ RAILVEH_WAGON
simple wagon, not motorized
Definition: engine_type.h:29
@ RAILVEH_MULTIHEAD
indicates a combination of two locomotives
Definition: engine_type.h:28
static const EngineID INVALID_ENGINE
Constant denoting an invalid engine.
Definition: engine_type.h:206
uint16_t EngineID
Unique identification number of an engine.
Definition: engine_type.h:21
@ ENGINE_EXCLUSIVE_PREVIEW
This vehicle is in the exclusive preview stage, either being used or being offered to a company.
Definition: engine_type.h:184
@ EF_RAIL_TILTS
Rail vehicle tilts in curves.
Definition: engine_type.h:168
@ EF_RAIL_FLIPS
Rail vehicle has old depot-flip handling.
Definition: engine_type.h:172
Functions related to errors.
void ShowErrorMessage(StringID summary_msg, int x, int y, CommandCost cc)
Display an error message in a window.
Definition: error_gui.cpp:367
@ WL_CRITICAL
Critical errors, the MessageBox is shown in all cases.
Definition: error.h:27
Error reporting related functions.
fluid_settings_t * settings
FluidSynth settings handle.
Definition: fluidsynth.cpp:21
Types for recording game performance data.
@ PFE_GL_TRAINS
Time spent processing trains.
Base functions for all Games.
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition: gfx_type.h:18
uint32_t PaletteID
The number of the palette.
Definition: gfx_type.h:19
@ AS_BRAKE
We want to stop.
@ GVF_SUPPRESS_IMPLICIT_ORDERS
Disable insertion and removal of automatic orders until the vehicle completes the real order.
@ GVF_GOINGDOWN_BIT
Vehicle is currently going downhill. (Cached track information for acceleration)
@ GVF_GOINGUP_BIT
Vehicle is currently going uphill. (Cached track information for acceleration)
void UpdateTrainGroupID(Train *v)
Recalculates the groupID of a train.
Definition: group_cmd.cpp:773
void SetTrainGroupID(Train *v, GroupID grp)
Affect the groupID of a train to new_g.
Definition: group_cmd.cpp:745
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
Mark a tile given by its index dirty for repaint.
Definition: viewport.cpp:2057
static const GroupID DEFAULT_GROUP
Ungrouped vehicles are in this group.
Definition: group_type.h:17
TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
Returns information about trackdirs and signal states.
Definition: landscape.cpp:554
int GetSlopePixelZ(int x, int y, bool ground_vehicle)
Return world Z coordinate of a given point of a tile.
Definition: landscape.cpp:303
DiagDirection DiagdirBetweenTiles(TileIndex tile_from, TileIndex tile_to)
Determines the DiagDirection to get from one tile to another.
Definition: map_func.h:620
TileIndex TileAddByDiagDir(TileIndex tile, DiagDirection dir)
Adds a DiagDir to a tile.
Definition: map_func.h:608
TileIndexDiff TileOffsByAxis(Axis axis)
Convert an Axis to a TileIndexDiff.
Definition: map_func.h:552
static debug_inline uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition: map_func.h:425
static debug_inline uint TileX(TileIndex tile)
Get the X component of a tile.
Definition: map_func.h:415
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition: map_func.h:567
static debug_inline TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition: map_func.h:404
int32_t TileIndexDiff
An offset value between two tiles.
Definition: map_type.h:23
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition: math_func.hpp:23
constexpr uint CeilDiv(uint a, uint b)
Computes ceil(a / b) for non-negative a and b.
Definition: math_func.hpp:320
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition: math_func.hpp:79
constexpr void Swap(T &a, T &b)
Type safe swap operation.
Definition: math_func.hpp:283
Miscellaneous command definitions.
void HideFillingPercent(TextEffectID *te_id)
Hide vehicle loading indicators.
Definition: misc_gui.cpp:648
bool _networking
are we in networking mode?
Definition: network.cpp:65
Basic functions/variables used all over the place.
ClientID
'Unique' identifier to be given to clients
Definition: network_type.h:49
Base for the NewGRF implementation.
@ SAT_TRAIN_ARRIVES
Trigger platform when train arrives.
@ CBID_VEHICLE_LENGTH
Vehicle length, returns the amount of 1/8's the vehicle is shorter for trains and RVs.
@ CBID_TRAIN_ALLOW_WAGON_ATTACH
Determine whether a wagon can be attached to an already existing train.
@ CBM_VEHICLE_LENGTH
Vehicle length (trains and road vehicles)
@ CBM_VEHICLE_ARTIC_ENGINE
Add articulated engines (trains and road vehicles)
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
void ErrorUnknownCallbackResult(uint32_t grfid, uint16_t cbid, uint16_t cb_res)
Record that a NewGRF returned an unknown/invalid callback result.
@ GBUG_VEH_CAPACITY
Capacity of vehicle changes when not refitting or arranging.
Definition: newgrf_config.h:47
Functions/types related to NewGRF debugging.
void InvalidateNewGRFInspectWindow(GrfSpecFeature feature, uint index)
Invalidate the inspect window for a given feature and index.
void DeleteNewGRFInspectWindow(GrfSpecFeature feature, uint index)
Delete inspect window for a given feature and index.
uint16_t GetVehicleCallbackParent(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v, const Vehicle *parent)
Evaluate a newgrf callback for vehicles with a different vehicle for parent scope.
bool UsesWagonOverride(const Vehicle *v)
Check if a wagon is currently using a wagon override.
bool TestVehicleBuildProbability(Vehicle *v, EngineID engine, BuildProbabilityType type)
Test for vehicle build probablity type.
uint16_t GetVehicleCallback(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v)
Evaluate a newgrf callback for vehicles.
@ PROP_TRAIN_SHORTEN_FACTOR
Shorter vehicles.
@ PROP_TRAIN_USER_DATA
User defined data for vehicle variable 0x42.
@ PROP_TRAIN_WEIGHT
Weight in t (if dualheaded: for each single vehicle)
@ PROP_TRAIN_CARGO_AGE_PERIOD
Number of ticks before carried cargo is aged.
@ PROP_TRAIN_RUNNING_COST_FACTOR
Yearly runningcost (if dualheaded: sum of both vehicles)
@ PROP_TRAIN_SPEED
Max. speed: 1 unit = 1/1.6 mph = 1 km-ish/h.
bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event, bool force)
Checks whether a NewGRF wants to play a different vehicle sound effect.
Functions related to NewGRF provided sounds.
@ VSE_START
Vehicle starting, i.e. leaving, the station.
Definition: newgrf_sound.h:19
void TriggerStationRandomisation(Station *st, TileIndex trigger_tile, StationRandomTrigger trigger, CargoID cargo_type)
Trigger station randomisation.
Header file for NewGRF stations.
@ SRT_TRAIN_ARRIVES
Trigger platform when train arrives.
StringID GetGRFStringID(uint32_t grfid, StringID stringid)
Returns the index for this stringid associated with its grfID.
Header of Action 04 "universal holder" structure and functions.
Functions related to news.
void AddVehicleAdviceNewsItem(StringID string, VehicleID vehicle)
Adds a vehicle-advice news item.
Definition: news_func.h:40
void AddVehicleNewsItem(StringID string, NewsType type, VehicleID vehicle, StationID station=INVALID_STATION)
Adds a newsitem referencing a vehicle.
Definition: news_func.h:30
@ NT_ARRIVAL_COMPANY
First vehicle arrived for company.
Definition: news_type.h:24
@ NT_ARRIVAL_OTHER
First vehicle arrived for competitor.
Definition: news_type.h:25
@ NT_ACCIDENT
An accident or disaster has occurred.
Definition: news_type.h:26
@ PM_PAUSED_ERROR
A game paused because a (critical) error.
Definition: openttd.h:73
Functions related to order backups.
bool ProcessOrders(Vehicle *v)
Handle the orders of a vehicle and determine the next place to go to if needed.
Definition: order_cmd.cpp:2127
bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead)
Update the vehicle's destination tile from an order.
Definition: order_cmd.cpp:1998
void CheckOrders(const Vehicle *v)
Check the orders of a vehicle, to see if there are invalid orders and stuff.
Definition: order_cmd.cpp:1711
void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices)
Delete all orders from a vehicle.
Definition: order_cmd.cpp:1869
VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
Process a conditional order and determine the next order.
Definition: order_cmd.cpp:1968
@ ODATFB_NEAREST_DEPOT
Send the vehicle to the nearest depot.
Definition: order_type.h:105
OrderStopLocation
Where to stop the trains.
Definition: order_type.h:83
@ OSL_PLATFORM_MIDDLE
Stop at the middle of the platform.
Definition: order_type.h:85
@ OSL_PLATFORM_FAR_END
Stop at the far end of the platform.
Definition: order_type.h:86
@ OSL_PLATFORM_NEAR_END
Stop at the near end of the platform.
Definition: order_type.h:84
uint8_t VehicleOrderID
The index of an order within its current vehicle (not pool related)
Definition: order_type.h:15
@ ONSF_NO_STOP_AT_DESTINATION_STATION
The vehicle will stop at any station it passes except the destination.
Definition: order_type.h:75
@ ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS
The vehicle will not stop at any stations it passes except the destination.
Definition: order_type.h:74
@ ODTFB_SERVICE
This depot order is because of the servicing limit.
Definition: order_type.h:95
static const VehicleOrderID INVALID_VEH_ORDER_ID
Invalid vehicle order index (sentinel)
Definition: order_type.h:21
OrderType
Order types.
Definition: order_type.h:35
void SetRailStationPlatformReservation(TileIndex start, DiagDirection dir, bool b)
Set the reservation for a complete station platform.
Definition: pbs.cpp:57
TrackBits GetReservedTrackbits(TileIndex t)
Get the reserved trackbits for any tile, regardless of type.
Definition: pbs.cpp:24
PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res)
Follow a train reservation to the last tile.
Definition: pbs.cpp:288
bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations)
Try to reserve a specific track on a tile.
Definition: pbs.cpp:80
bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg)
Check if a safe position is free.
Definition: pbs.cpp:426
void UnreserveRailTrack(TileIndex tile, Track t)
Lift the reservation of a specific track on a tile.
Definition: pbs.cpp:140
bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bool include_line_end, bool forbid_90deg)
Determine whether a certain track on a tile is a safe position to end a path.
Definition: pbs.cpp:380
bool HasReservedTracks(TileIndex tile, TrackBits tracks)
Check whether some of tracks is reserved on a tile.
Definition: pbs.h:58
RailType GetTileRailType(Tile tile)
Return the rail type of tile, or INVALID_RAILTYPE if this is no rail tile.
Definition: rail.cpp:155
int TicksToLeaveDepot(const Train *v)
Compute number of ticks when next wagon will leave a depot.
Definition: rail_cmd.cpp:2916
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition: rail.h:307
bool IsCompatibleRail(RailType enginetype, RailType tiletype)
Checks if an engine of the given RailType can drive on a tile with a given RailType.
Definition: rail.h:322
bool HasPowerOnRail(RailType enginetype, RailType tiletype)
Checks if an engine of the given RailType got power on a tile with a given RailType.
Definition: rail.h:335
bool Rail90DegTurnDisallowed(RailType rt1, RailType rt2, bool def=_settings_game.pf.forbid_90_deg)
Test if 90 degree turns are disallowed between two railtypes.
Definition: rail.h:357
std::vector< Train * > TrainList
Helper type for lists/vectors of trains.
Definition: rail_cmd.cpp:44
bool HasOnewaySignalBlockingTrackdir(Tile tile, Trackdir td)
Is a one-way signal blocking the trackdir? A one-way signal on the trackdir against will block,...
Definition: rail_map.h:475
RailType GetRailType(Tile t)
Gets the rail type of the given tile.
Definition: rail_map.h:115
bool HasSignalOnTrackdir(Tile tile, Trackdir trackdir)
Checks for the presence of signals along the given trackdir on the given rail tile.
Definition: rail_map.h:426
static debug_inline RailTileType GetRailTileType(Tile t)
Returns the RailTileType (normal with or without signals, waypoint or depot).
Definition: rail_map.h:36
TrackBits GetTrackBits(Tile tile)
Gets the track bits of the given tile.
Definition: rail_map.h:136
static debug_inline bool IsRailDepotTile(Tile t)
Is this tile rail tile and a rail depot?
Definition: rail_map.h:105
Track GetRailDepotTrack(Tile t)
Returns the track of a depot, ignoring direction.
Definition: rail_map.h:182
DiagDirection GetRailDepotDirection(Tile t)
Returns the direction the depot is facing to.
Definition: rail_map.h:171
void SetSignalStateByTrackdir(Tile tile, Trackdir trackdir, SignalState state)
Sets the state of the signal along the given trackdir.
Definition: rail_map.h:449
bool HasPbsSignalOnTrackdir(Tile tile, Trackdir td)
Is a pbs signal present along the trackdir?
Definition: rail_map.h:463
bool IsOnewaySignal(Tile t, Track track)
One-way signals can't be passed the 'wrong' way.
Definition: rail_map.h:319
void SetDepotReservation(Tile t, bool b)
Set the reservation state of the depot.
Definition: rail_map.h:270
static debug_inline bool IsPlainRail(Tile t)
Returns whether this is plain rails, with or without signals.
Definition: rail_map.h:49
bool HasDepotReservation(Tile t)
Get the reservation state of the depot.
Definition: rail_map.h:258
@ RAIL_TILE_SIGNALS
Normal rail tile with signals.
Definition: rail_map.h:25
bool HasSignals(Tile t)
Checks if a rail tile has signals.
Definition: rail_map.h:72
static debug_inline bool IsPlainRailTile(Tile t)
Checks whether the tile is a rail tile or rail tile with signals.
Definition: rail_map.h:60
SignalState GetSignalStateByTrackdir(Tile tile, Trackdir trackdir)
Gets the state of the signal along the given trackdir.
Definition: rail_map.h:438
@ RAILTYPES_RAIL
Non-electrified rails.
Definition: rail_type.h:46
@ RAILTYPES_NONE
No rail types.
Definition: rail_type.h:45
@ RAILTYPE_RAIL
Standard non-electric rails.
Definition: rail_type.h:29
Pseudo random number generator.
bool Chance16(const uint32_t a, const uint32_t b, const std::source_location location=std::source_location::current())
Flips a coin with given probability.
bool Chance16R(const uint32_t a, const uint32_t b, uint32_t &r, const std::source_location location=std::source_location::current())
Flips a coin with a given probability and saves the randomize-number in a variable.
bool HasCrossingReservation(Tile t)
Get the reservation state of the rail crossing.
Definition: road_map.h:380
bool IsLevelCrossingTile(Tile t)
Return whether a tile is a level crossing tile.
Definition: road_map.h:95
Axis GetCrossingRoadAxis(Tile t)
Get the road axis of a level crossing.
Definition: road_map.h:325
void SetCrossingBarred(Tile t, bool barred)
Set the bar state of a level crossing.
Definition: road_map.h:428
Axis GetCrossingRailAxis(Tile t)
Get the rail axis of a level crossing.
Definition: road_map.h:337
bool IsCrossingBarred(Tile t)
Check if the level crossing is barred.
Definition: road_map.h:416
void SetCrossingReservation(Tile t, bool b)
Set the reservation state of the rail crossing.
Definition: road_map.h:393
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition: settings.cpp:57
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:56
SigSegState UpdateSignalsOnSegment(TileIndex tile, DiagDirection side, Owner owner)
Update signals, starting at one side of a tile Will check tile next to this at opposite side too.
Definition: signal.cpp:650
static SigSegState UpdateSignalsInBuffer(Owner owner)
Updates blocks in _globset buffer.
Definition: signal.cpp:482
void AddSideToSignalBuffer(TileIndex tile, DiagDirection side, Owner owner)
Add side of tile to signal update buffer.
Definition: signal.cpp:624
void SetSignalsOnBothDir(TileIndex tile, Track track, Owner owner)
Update signals at segments that are at both ends of given (existent or non-existent) track.
Definition: signal.cpp:668
SigSegState
State of the signal segment.
Definition: signal_func.h:49
@ SIGSEG_PBS
Segment is a PBS segment.
Definition: signal_func.h:52
@ SIGSEG_FULL
Occupied by a train.
Definition: signal_func.h:51
@ SIGTYPE_PBS
normal pbs signal
Definition: signal_type.h:28
@ SIGNAL_STATE_RED
The signal is red.
Definition: signal_type.h:43
@ SIGNAL_STATE_GREEN
The signal is green.
Definition: signal_type.h:44
Functions related to sound.
SoundFx
Sound effects from baseset.
Definition: sound_type.h:37
@ SND_04_DEPARTURE_STEAM
2 == 0x02 Station departure: steam engine
Definition: sound_type.h:41
@ SND_41_DEPARTURE_MAGLEV
65 == 0x41 Station departure: maglev engine
Definition: sound_type.h:104
@ SND_13_TRAIN_COLLISION
15 == 0x11 Train+train crash
Definition: sound_type.h:56
@ SND_0E_LEVEL_CROSSING
12 == 0x0C Train passes through level crossing
Definition: sound_type.h:51
@ SND_0A_DEPARTURE_TRAIN
8 == 0x08 Station departure: diesel and electric engine
Definition: sound_type.h:47
@ SND_47_DEPARTURE_MONORAIL
71 == 0x47 Station departure: monorail engine
Definition: sound_type.h:110
Functions to cache sprites in memory.
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition: sprites.h:1605
bool IsRailWaypointTile(Tile t)
Is this tile a station tile and a rail waypoint?
Definition: station_map.h:123
bool IsCompatibleTrainStationTile(Tile test_tile, Tile station_tile)
Check if a tile is a valid continuation to a railstation tile.
Definition: station_map.h:544
bool IsRailStationTile(Tile t)
Is this tile a station tile and a rail station?
Definition: station_map.h:102
StationID GetStationIndex(Tile t)
Get StationID from a tile.
Definition: station_map.h:28
Axis GetRailStationAxis(Tile t)
Get the rail direction of a rail station.
Definition: station_map.h:503
@ HVOT_TRAIN
Station has seen a train.
Definition: station_type.h:66
@ FACIL_TRAIN
Station with train station.
Definition: station_type.h:54
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
Definition: stdafx.h:280
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings.cpp:104
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Definition: strings_type.h:17
Data structure for storing engine speed changes of an acceleration type.
Definition: train_cmd.cpp:3039
uint8_t large_turn
Speed change due to a large turn.
Definition: train_cmd.cpp:3041
uint8_t z_up
Fraction to remove when moving up.
Definition: train_cmd.cpp:3042
uint8_t small_turn
Speed change due to a small turn.
Definition: train_cmd.cpp:3040
uint8_t z_down
Fraction to add when moving down.
Definition: train_cmd.cpp:3043
std::string name
Name of vehicle.
Definition: base_consist.h:18
TimerGameTick::Ticks current_order_time
How many ticks have passed since this order started.
Definition: base_consist.h:21
VehicleOrderID cur_real_order_index
The index to the current real (non-implicit) order.
Definition: base_consist.h:31
uint16_t vehicle_flags
Used for gradual loading and other miscellaneous things (.
Definition: base_consist.h:34
void ResetDepotUnbunching()
Resets all the data used for depot unbunching.
StationFacility facilities
The facilities that this station has.
TileIndex xy
Base tile of the station.
TileArea train_station
Tile area the train 'station' part covers.
VehicleType type
Type of vehicle.
Definition: vehicle_type.h:51
uint16_t speed
maximum travel speed (1 unit = 1/1.6 mph = 1 km-ish/h)
Definition: bridge.h:47
Track follower helper template class (can serve pathfinders and vehicle controllers).
bool Follow(TileIndex old_tile, Trackdir old_td)
main follower routine.
bool is_tunnel
last turn passed tunnel
bool is_bridge
last turn passed bridge ramp
int tiles_skipped
number of skipped tunnel or station tiles
DiagDirection exitdir
exit direction (leaving the old tile)
TrackdirBits new_td_bits
the new set of available trackdirs
TileIndex new_tile
the new tile (the vehicle has entered)
Trackdir old_td
the trackdir (the vehicle was on) before move
bool is_station
last turn passed station
TileIndex old_tile
the origin (vehicle moved from) before move
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo ID.
Definition: cargotype.h:134
SoundSettings sound
sound effect settings
GUISettings gui
settings related to the GUI
Structure to return information about the closest depot location, and whether it could be found.
Definition: vehicle_base.h:230
bool line_reverse_mode
reversing at stations or not
uint16_t cargo_age_period
Number of ticks before carried cargo is aged.
Definition: engine_type.h:159
uint8_t misc_flags
Miscellaneous flags.
Definition: engine_type.h:155
uint16_t callback_mask
Bitmask of vehicle callbacks that have to be called.
Definition: engine_type.h:156
CargoID GetDefaultCargoType() const
Determines the default cargo type of an engine.
Definition: engine_base.h:96
uint32_t GetGRFID() const
Retrieve the GRF ID of the NewGRF the engine is tied to.
Definition: engine.cpp:157
uint16_t reliability_spd_dec
Speed of reliability decay between services (per day).
Definition: engine_base.h:42
uint DetermineCapacity(const Vehicle *v, uint16_t *mail_capacity=nullptr) const
Determines capacity of a given vehicle from scratch.
Definition: engine.cpp:201
uint8_t original_image_index
Original vehicle image index, thus the image index of the overridden vehicle.
Definition: engine_base.h:55
const GRFFile * GetGRF() const
Retrieve the NewGRF the engine is tied to.
Definition: engine_base.h:167
TimerGameCalendar::Date GetLifeLengthInDays() const
Returns the vehicle's (not model's!) life length in days.
Definition: engine.cpp:443
uint16_t reliability
Current reliability of the engine.
Definition: engine_base.h:41
uint8_t flags
Flags of the engine.
Definition: engine_base.h:49
Helper container to find a depot.
uint best_length
The distance towards the depot in penalty, or UINT_MAX if not found.
bool reverse
True if reversing is necessary for the train to get to this depot.
TileIndex tile
The tile of the depot.
uint traininfo_vehicle_width
Width (in pixels) of a 8/8 train vehicle in depot GUI and vehicle details.
Definition: newgrf.h:147
int traininfo_vehicle_pitch
Vertical offset for drawing train images in depot GUI and vehicle details.
Definition: newgrf.h:146
bool lost_vehicle_warn
if a vehicle can't find its destination, show a warning
bool show_track_reservation
highlight reserved tracks.
PathfinderSettings pf
settings for all pathfinders
DifficultySettings difficulty
settings related to the difficulty
VehicleSettings vehicle
options for vehicles
Position information of a vehicle after it moved.
Definition: vehicle_func.h:77
TileIndex new_tile
Tile of the vehicle after moving.
Definition: vehicle_func.h:80
int y
x and y position of the vehicle after moving
Definition: vehicle_func.h:78
TileIndex old_tile
Current tile of the vehicle.
Definition: vehicle_func.h:79
uint32_t cached_weight
Total weight of the consist (valid only for the first engine).
EngineID first_engine
Cached EngineID of the front vehicle. INVALID_ENGINE for the front vehicle itself.
uint32_t cached_power
Total power of the consist (valid only for the first engine).
uint16_t cached_total_length
Length of the whole vehicle (valid only for the first engine).
uint8_t cached_veh_length
Length of this vehicle in units of 1/VEHICLE_LENGTH of normal length. It is cached because this can b...
uint16_t cached_max_track_speed
Maximum consist speed (in internal units) limited by track type (valid only for the first engine).
bool IsChainInDepot() const override
Check whether the whole vehicle chain is in the depot.
void SetFreeWagon()
Set a vehicle as a free wagon.
int UpdateInclination(bool new_tile, bool update_delta)
Checks if the vehicle is in a slope and sets the required flags in that case.
GroundVehicleCache gcache
Cache of often calculated values.
void CargoChanged()
Recalculates the cached weight of a vehicle and its parts.
void SetMultiheaded()
Set a vehicle as a multiheaded engine.
bool IsEngine() const
Check if a vehicle is an engine (can be first in a consist).
bool IsRearDualheaded() const
Tell if we are dealing with the rear end of a multiheaded engine.
bool IsMultiheaded() const
Check if the vehicle is a multiheaded engine.
void SetEngine()
Set engine status.
void SetWagon()
Set a vehicle to be a wagon.
void SetFrontEngine()
Set front engine state.
void ClearFreeWagon()
Clear a vehicle from being a free wagon.
bool IsWagon() const
Check if a vehicle is a wagon.
uint Crash(bool flooded) override
Common code executed for crashed ground vehicles.
bool IsFreeWagon() const
Check if the vehicle is a free wagon (got no engine in front of it).
uint DoUpdateSpeed(uint accel, int min_speed, int max_speed)
Update the speed of the vehicle.
int GetAcceleration() const
Calculates the acceleration of the vehicle under its current conditions.
void ClearFrontEngine()
Remove the front engine state.
void SetLastSpeed()
Update the GUI variant of the current speed of the vehicle.
static void CountVehicle(const Vehicle *v, int delta)
Update num_vehicle when adding or removing a vehicle.
Definition: group_cmd.cpp:133
static debug_inline uint Size()
Get the size of the map.
Definition: map_func.h:288
VehicleSpriteSeq sprite_seq
Vehicle appearance.
Definition: vehicle_base.h:200
static void Backup(const Vehicle *v, uint32_t user)
Create an order backup for the given vehicle.
OrderDepotTypeFlags GetDepotOrderType() const
What caused us going to the depot?
Definition: order_base.h:144
uint16_t GetMaxSpeed() const
Get the maxmimum speed in km-ish/h a vehicle is allowed to reach on the way to the destination.
Definition: order_base.h:201
DestinationID GetDestination() const
Gets the destination of this order.
Definition: order_base.h:103
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition: order_base.h:70
OrderStopLocation GetStopLocation() const
Where must we stop at the platform?
Definition: order_base.h:142
OrderType GetType() const
Get the type of order of this order.
Definition: order_base.h:76
void MakeDummy()
Makes this order a Dummy order.
Definition: order_cmd.cpp:133
void MakeGoToDepot(DepotID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type=ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS, OrderDepotActionFlags action=ODATF_SERVICE_ONLY, CargoID cargo=CARGO_NO_REFIT)
Makes this order a Go To Depot order.
Definition: order_cmd.cpp:90
void SetDestination(DestinationID destination)
Sets the destination of this order.
Definition: order_base.h:110
OrderDepotActionFlags GetDepotActionType() const
What are we going to do when in the depot.
Definition: order_base.h:146
void Free()
'Free' the order
Definition: order_cmd.cpp:63
bool ShouldStopAtStation(const Vehicle *v, StationID station) const
Check whether the given vehicle should stop at the given station based on this order and the non-stop...
Definition: order_cmd.cpp:2225
OrderNonStopFlags GetNonStopType() const
At which stations must we stop?
Definition: order_base.h:140
TileIndex tile
The base tile of the area.
Definition: tilearea_type.h:19
This struct contains information about the end of a reserved path.
Definition: pbs.h:26
Trackdir trackdir
The reserved trackdir on the tile.
Definition: pbs.h:28
TileIndex tile
Tile the path ends, INVALID_TILE if no valid path was found.
Definition: pbs.h:27
bool okay
True if tile is a safe waiting position, false otherwise.
Definition: pbs.h:29
uint8_t path_backoff_interval
ticks between checks for a free path.
uint8_t wait_for_pbs_path
how long to wait for a path reservation.
uint8_t wait_oneway_signal
waitingtime in days before a oneway signal
bool reserve_paths
always reserve paths regardless of signal type.
YAPFSettings yapf
pathfinder settings for the yet another pathfinder
bool reverse_at_signals
whether to reverse at signals at all
bool forbid_90_deg
forbid trains to make 90 deg turns
uint8_t wait_twoway_signal
waitingtime in days before a twoway signal
Coordinates of a point in 2D.
Tindex index
Index of this pool item.
Definition: pool_type.hpp:238
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:339
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
Definition: pool_type.hpp:309
Information about a rail vehicle.
Definition: engine_type.h:42
uint16_t power
Power of engine (hp); For multiheaded engines the sum of both engine powers.
Definition: engine_type.h:49
uint8_t user_def_data
Property 0x25: "User-defined bit mask" Used only for (very few) NewGRF vehicles.
Definition: engine_type.h:62
uint8_t running_cost
Running cost of engine; For multiheaded engines the sum of both running costs.
Definition: engine_type.h:51
uint8_t shorten_factor
length on main map for this type is 8 - shorten_factor
Definition: engine_type.h:59
uint16_t pow_wag_power
Extra power applied to consist if wagon should be powered.
Definition: engine_type.h:56
uint16_t max_speed
Maximum speed (1 unit = 1/1.6 mph = 1 km-ish/h)
Definition: engine_type.h:48
uint8_t capacity
Cargo capacity of vehicle; For multiheaded engines the capacity of each single engine.
Definition: engine_type.h:54
RailType railtype
Railtype, mangled if elrail is disabled.
Definition: engine_type.h:46
uint8_t pow_wag_weight
Extra weight applied to consist if wagon should be powered.
Definition: engine_type.h:57
Specification of a rectangle with absolute coordinates of all edges.
int Width() const
Get width of Rect.
int Height() const
Get height of Rect.
Iterable ensemble of each set bit in a value.
bool ambient
Play ambient, industry and town sounds.
bool disaster
Play disaster and accident sounds.
static Station * Get(size_t index)
Gets station with given index.
T * Previous() const
Get previous vehicle in the chain.
T * GetLastEnginePart()
Get the last part of an articulated engine.
T * Last()
Get the last vehicle in the chain.
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
T * GetNextVehicle() const
Get the next real (non-articulated part) vehicle in the consist.
T * Next() const
Get next vehicle in the chain.
void UpdateViewport(bool force_update, bool update_delta)
Update vehicle sprite- and position caches.
T * GetFirstEnginePart()
Get the first part of an articulated engine.
static Pool::IterateWrapper< T > Iterate(size_t from=0)
Returns an iterable ensemble of all valid vehicles of type T.
T * First() const
Get the first vehicle in the chain.
static T * GetIfValid(size_t index)
Returns vehicle if the index is a valid index for this vehicle type.
Station data structure.
Definition: station_base.h:439
uint GetPlatformLength(TileIndex tile, DiagDirection dir) const override
Determines the REMAINING length of a platform, starting at (and including) the given tile.
Definition: station.cpp:285
uint16_t cached_max_curve_speed
max consist speed limited by curves
Definition: train.h:81
int16_t cached_curve_speed_mod
curve speed modifier of the entire train
Definition: train.h:80
bool cached_tilt
train can tilt; feature provides a bonus in curves
Definition: train.h:77
Temporary data storage for testing collisions.
Definition: train_cmd.cpp:3168
Train * v
Vehicle we are testing for collision.
Definition: train_cmd.cpp:3169
uint num
Total number of victims if train collided.
Definition: train_cmd.cpp:3170
'Train' is either a loco or a wagon.
Definition: train.h:89
void PlayLeaveStationSound(bool force=false) const override
Play a sound for a train leaving the station.
Definition: train_cmd.cpp:2182
Train * GetNextUnit() const
Get the next real (non-articulated part and non rear part of dualheaded engine) vehicle in the consis...
Definition: train.h:148
void UpdateAcceleration()
Update acceleration of the train from the cached power and weight.
Definition: train_cmd.cpp:430
void OnNewCalendarDay() override
Calendar day handler.
Definition: train_cmd.cpp:4176
Trackdir GetVehicleTrackdir() const override
Get the tracks of the train vehicle.
Definition: train_cmd.cpp:4220
void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const override
Get the sprite to display the train.
Definition: train_cmd.cpp:494
uint16_t crash_anim_pos
Crash animation counter.
Definition: train.h:91
bool Tick() override
Update train vehicle data for a tick.
Definition: train_cmd.cpp:4109
void ReserveTrackUnderConsist() const
Tries to reserve track under whole train consist.
Definition: train_cmd.cpp:3088
TileIndex GetOrderStationLocation(StationID station) override
Get the location of the next station to visit.
Definition: train_cmd.cpp:2951
int GetDisplayImageWidth(Point *offset=nullptr) const
Get the width of a train vehicle image in the GUI.
Definition: train_cmd.cpp:460
ClosestDepot FindClosestDepot() override
Find the closest depot for this vehicle and tell us the location, DestinationID and whether we should...
Definition: train_cmd.cpp:2173
void UpdateDeltaXY() override
Updates the x and y offsets and the size of the sprite used for this vehicle.
Definition: train_cmd.cpp:1465
int CalcNextVehicleOffset() const
Calculate the offset from this vehicle's center to the following center taking the vehicle lengths in...
Definition: train.h:172
uint16_t GetMaxWeight() const override
Calculates the weight value that this vehicle will have when fully loaded with its current cargo.
Definition: train_cmd.cpp:4237
uint16_t GetCurveSpeedLimit() const
Computes train speed limit caused by curves.
Definition: train_cmd.cpp:307
bool IsPrimaryVehicle() const override
Whether this is the primary vehicle in the chain.
Definition: train.h:116
void MarkDirty() override
Goods at the consist have changed, update the graphics, cargo, and acceleration.
Definition: train_cmd.cpp:2966
int UpdateSpeed()
This function looks at the vehicle and updates its speed (cur_speed and subspeed) variables.
Definition: train_cmd.cpp:2986
uint Crash(bool flooded=false) override
The train vehicle crashed! Update its status and other parts around it.
Definition: train_cmd.cpp:3110
AccelStatus GetAccelerationStatus() const
Checks the current acceleration status of this vehicle.
Definition: train.h:273
void OnNewEconomyDay() override
Economy day handler.
Definition: train_cmd.cpp:4182
void ConsistChanged(ConsistChangeFlags allowed_changes)
Recalculates the cached stuff of a train.
Definition: train_cmd.cpp:110
Money GetRunningCost() const override
Get running cost for the train consist.
Definition: train_cmd.cpp:4084
uint16_t wait_counter
Ticks waiting in front of a signal, ticks being stuck or a counter for forced proceeding through sign...
Definition: train.h:92
int GetCurrentMaxSpeed() const override
Calculates the maximum speed of the vehicle under its current conditions.
Definition: train_cmd.cpp:382
uint16_t cached_max_speed
Maximum speed of the consist (minimum of the max speed of all vehicles in the consist).
Definition: vehicle_base.h:126
UnitID max_trains
max trains in game per company
uint8_t train_acceleration_model
realistic acceleration for trains
bool wagon_speed_limits
enable wagon speed limits
uint8_t freight_trains
value to multiply the weight of cargo by
uint8_t max_train_length
maximum length for trains
Sprite sequence for a vehicle part.
Definition: vehicle_base.h:135
void GetBounds(Rect *bounds) const
Determine shared bounds of all sprites.
Definition: vehicle.cpp:103
void Set(SpriteID sprite)
Assign a single sprite to the sequence.
Definition: vehicle_base.h:168
void Draw(int x, int y, PaletteID default_pal, bool force_pal) const
Draw the sprite sequence.
Definition: vehicle.cpp:131
Vehicle data structure.
Definition: vehicle_base.h:244
EngineID engine_type
The type of engine used for this vehicle.
Definition: vehicle_base.h:323
int32_t z_pos
z coordinate.
Definition: vehicle_base.h:306
Direction direction
facing
Definition: vehicle_base.h:307
const Engine * GetEngine() const
Retrieves the engine of the vehicle.
Definition: vehicle.cpp:747
void IncrementRealOrderIndex()
Advanced cur_real_order_index to the next real order, keeps care of the wrap-around and invalidates t...
Definition: vehicle_base.h:886
bool IsStoppedInDepot() const
Check whether the vehicle is in the depot and stopped.
Definition: vehicle_base.h:560
void LeaveStation()
Perform all actions when leaving a station.
Definition: vehicle.cpp:2350
void AddToShared(Vehicle *shared_chain)
Adds this vehicle to a shared vehicle chain.
Definition: vehicle.cpp:2966
VehicleCargoList cargo
The cargo this vehicle is carrying.
Definition: vehicle_base.h:341
uint8_t x_extent
x-extent of vehicle bounding box
Definition: vehicle_base.h:316
TimerGameEconomy::Date date_of_last_service
Last economy date the vehicle had a service at a depot.
Definition: vehicle_base.h:295
uint16_t cargo_cap
total capacity
Definition: vehicle_base.h:344
StationID last_loading_station
Last station the vehicle has stopped at and could possibly leave from with any cargo loaded.
Definition: vehicle_base.h:338
VehicleOrderID GetNumOrders() const
Get the number of orders this vehicle has.
Definition: vehicle_base.h:738
uint16_t random_bits
Bits used for randomized variational spritegroups.
Definition: vehicle_base.h:335
void ReleaseUnitNumber()
Release the vehicle's unit number.
Definition: vehicle.cpp:2419
uint8_t day_counter
Increased by one for each day.
Definition: vehicle_base.h:349
void HandleLoading(bool mode=false)
Handle the loading of the vehicle; when not it skips through dummy orders and does nothing in all oth...
Definition: vehicle.cpp:2430
Money profit_this_year
Profit this year << 8, low 8 bits are fract.
Definition: vehicle_base.h:273
SpriteID colourmap
NOSAVE: cached colour mapping.
Definition: vehicle_base.h:288
uint8_t breakdown_ctr
Counter for managing breakdown events.
Definition: vehicle_base.h:299
uint GetAdvanceDistance()
Determines the vehicle "progress" needed for moving a step.
Definition: vehicle_base.h:457
GroupID group_id
Index of group Pool array.
Definition: vehicle_base.h:366
uint8_t z_extent
z-extent of vehicle bounding box
Definition: vehicle_base.h:318
TimerGameCalendar::Date date_of_last_service_newgrf
Last calendar date the vehicle had a service at a depot, unchanged by the date cheat to protect again...
Definition: vehicle_base.h:296
Order * GetOrder(int index) const
Returns order 'index' of a vehicle or nullptr when it doesn't exists.
Definition: vehicle_base.h:922
uint8_t subspeed
fractional speed
Definition: vehicle_base.h:329
bool IsArticulatedPart() const
Check if the vehicle is an articulated part of an engine.
Definition: vehicle_base.h:954
void LeaveUnbunchingDepot()
Leave an unbunching depot and calculate the next departure time for shared order vehicles.
Definition: vehicle.cpp:2514
int8_t y_offs
y offset for vehicle sprite
Definition: vehicle_base.h:322
Vehicle * Next() const
Get the next vehicle of this vehicle.
Definition: vehicle_base.h:632
debug_inline bool IsFrontEngine() const
Check if the vehicle is a front engine.
Definition: vehicle_base.h:945
uint8_t acceleration
used by train & aircraft
Definition: vehicle_base.h:330
int8_t x_bb_offs
x offset of vehicle bounding box
Definition: vehicle_base.h:319
Order current_order
The current order (+ status, like: loading)
Definition: vehicle_base.h:356
CargoID cargo_type
type of cargo this vehicle is carrying
Definition: vehicle_base.h:342
void HandlePathfindingResult(bool path_found)
Handle the pathfinding result, especially the lost status.
Definition: vehicle.cpp:791
int8_t x_offs
x offset for vehicle sprite
Definition: vehicle_base.h:321
int32_t y_pos
y coordinate.
Definition: vehicle_base.h:305
int32_t x_pos
x coordinate.
Definition: vehicle_base.h:304
const GRFFile * GetGRF() const
Retrieve the NewGRF the vehicle is tied to.
Definition: vehicle.cpp:757
OrderList * orders
Pointer to the order list for this vehicle.
Definition: vehicle_base.h:359
uint8_t y_extent
y-extent of vehicle bounding box
Definition: vehicle_base.h:317
Money value
Value of the vehicle.
Definition: vehicle_base.h:275
uint16_t refit_cap
Capacity left over from before last refit.
Definition: vehicle_base.h:345
void InvalidateNewGRFCache()
Invalidates cached NewGRF variables.
Definition: vehicle_base.h:495
uint8_t vehstatus
Status.
Definition: vehicle_base.h:354
VehicleCache vcache
Cache of often used vehicle values.
Definition: vehicle_base.h:364
uint32_t GetGRFID() const
Retrieve the GRF ID of the NewGRF the vehicle is tied to.
Definition: vehicle.cpp:767
int8_t y_bb_offs
y offset of vehicle bounding box
Definition: vehicle_base.h:320
void BeginLoading()
Prepare everything to begin the loading when arriving at a station.
Definition: vehicle.cpp:2203
uint8_t spritenum
currently displayed sprite index 0xfd == custom sprite, 0xfe == custom second head sprite 0xff == res...
Definition: vehicle_base.h:315
uint16_t cur_speed
current speed
Definition: vehicle_base.h:328
uint8_t cargo_subtype
Used for livery refits (NewGRF variations)
Definition: vehicle_base.h:343
bool IsWaitingForUnbunching() const
Check whether a vehicle inside a depot is waiting for unbunching.
Definition: vehicle.cpp:2561
TextEffectID fill_percent_te_id
a text-effect id to a loading indicator object
Definition: vehicle_base.h:325
void SetNext(Vehicle *next)
Set the next vehicle of this vehicle.
Definition: vehicle.cpp:2937
TimerGameCalendar::Date max_age
Maximum age.
Definition: vehicle_base.h:294
MutableSpriteCache sprite_cache
Cache of sprites and values related to recalculating them, see MutableSpriteCache.
Definition: vehicle_base.h:368
uint16_t reliability
Reliability.
Definition: vehicle_base.h:297
bool HandleBreakdown()
Handle all of the aspects of a vehicle breakdown This includes adding smoke and sounds,...
Definition: vehicle.cpp:1363
uint8_t progress
The percentage (if divided by 256) this vehicle already crossed the tile unit.
Definition: vehicle_base.h:332
uint16_t reliability_spd_dec
Reliability decrease speed.
Definition: vehicle_base.h:298
uint8_t tick_counter
Increased by one for each tick.
Definition: vehicle_base.h:350
TileIndex tile
Current tile index.
Definition: vehicle_base.h:264
TileIndex dest_tile
Heading for this tile.
Definition: vehicle_base.h:271
void CopyVehicleConfigAndStatistics(Vehicle *src)
Copy certain configurations and statistics of a vehicle after successful autoreplace/renew The functi...
Definition: vehicle_base.h:765
void UpdatePosition()
Update the position of the vehicle.
Definition: vehicle.cpp:1693
StationID last_station_visited
The last station we stopped at.
Definition: vehicle_base.h:337
void ShowVisualEffect() const
Draw visual effects (smoke and/or sparks) for a vehicle chain.
Definition: vehicle.cpp:2787
TimerGameCalendar::Year build_year
Year the vehicle has been built.
Definition: vehicle_base.h:291
Owner owner
Which company owns the vehicle?
Definition: vehicle_base.h:309
UnitID unitnumber
unit number, for display purposes only
Definition: vehicle_base.h:326
bool NeedsAutomaticServicing() const
Checks if the current order should be interrupted for a service-in-depot order.
Definition: vehicle.cpp:272
uint8_t running_ticks
Number of ticks this vehicle was not stopped this day.
Definition: vehicle_base.h:351
uint32_t maximum_go_to_depot_penalty
What is the maximum penalty that may be endured for going to a depot.
@ VETS_CANNOT_ENTER
The vehicle cannot enter the tile.
Definition: tile_cmd.h:24
@ VETS_ENTERED_WORMHOLE
The vehicle either entered a bridge, tunnel or depot tile (this includes the last tile of the bridge/...
Definition: tile_cmd.h:23
@ VETS_ENTERED_STATION
The vehicle entered a station.
Definition: tile_cmd.h:22
@ VETS_STATION_ID_OFFSET
Shift the VehicleEnterTileStatus this many bits to the right to get the station ID when VETS_ENTERED_...
Definition: tile_cmd.h:31
VehicleEnterTileStatus VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
Call the tile callback function for a vehicle entering a tile.
Definition: vehicle.cpp:1838
bool IsTileOwner(Tile tile, Owner owner)
Checks if a tile belongs to the given owner.
Definition: tile_map.h:214
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition: tile_map.h:178
static debug_inline bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition: tile_map.h:150
static const uint TILE_SIZE
Tile size in world coordinates.
Definition: tile_type.h:15
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition: tile_type.h:95
@ MP_STATION
A tile of a station.
Definition: tile_type.h:53
@ MP_TUNNELBRIDGE
Tunnel entry/exit and bridge heads.
Definition: tile_type.h:57
@ MP_RAILWAY
A railway.
Definition: tile_type.h:49
Definition of the game-calendar-timer.
Definition of the game-economy-timer.
Trackdir RemoveFirstTrackdir(TrackdirBits *trackdirs)
Removes first Trackdir from TrackdirBits and returns it.
Definition: track_func.h:156
Track TrackdirToTrack(Trackdir trackdir)
Returns the Track that a given Trackdir represents.
Definition: track_func.h:262
TrackBits TrackToTrackBits(Track track)
Maps a Track to the corresponding TrackBits value.
Definition: track_func.h:77
TrackdirBits TrackBitsToTrackdirBits(TrackBits bits)
Converts TrackBits to TrackdirBits while allowing both directions.
Definition: track_func.h:319
DiagDirection VehicleExitDir(Direction direction, TrackBits track)
Determine the side in which the vehicle will leave the tile.
Definition: track_func.h:714
TrackdirBits TrackStatusToTrackdirBits(TrackStatus ts)
Returns the present-trackdir-information of a TrackStatus.
Definition: track_func.h:352
Track TrackBitsToTrack(TrackBits tracks)
Converts TrackBits to Track.
Definition: track_func.h:193
TrackBits TrackCrossesTracks(Track track)
Maps a track to all tracks that make 90 deg turns with it.
Definition: track_func.h:420
Trackdir ReverseTrackdir(Trackdir trackdir)
Maps a trackdir to the reverse trackdir.
Definition: track_func.h:247
bool TracksOverlap(TrackBits bits)
Checks if the given tracks overlap, ie form a crossing.
Definition: track_func.h:645
Trackdir TrackDirectionToTrackdir(Track track, Direction dir)
Maps a track and a full (8-way) direction to the trackdir that represents the track running in the gi...
Definition: track_func.h:498
bool IsValidTrackdir(Trackdir trackdir)
Checks if a Trackdir is valid for non-road vehicles.
Definition: track_func.h:52
Trackdir FindFirstTrackdir(TrackdirBits trackdirs)
Returns first Trackdir from TrackdirBits or INVALID_TRACKDIR.
Definition: track_func.h:211
TrackdirBits TrackdirCrossesTrackdirs(Trackdir trackdir)
Maps a trackdir to all trackdirs that make 90 deg turns with it.
Definition: track_func.h:606
TrackdirBits TrackdirReachesTrackdirs(Trackdir trackdir)
Maps a trackdir to the trackdirs that can be reached from it (ie, when entering the next tile.
Definition: track_func.h:584
TrackdirBits DiagdirReachesTrackdirs(DiagDirection diagdir)
Returns all trackdirs that can be reached when entering a tile from a given (diagonal) direction.
Definition: track_func.h:555
Track FindFirstTrack(TrackBits tracks)
Returns first Track from TrackBits or INVALID_TRACK.
Definition: track_func.h:177
Trackdir TrackEnterdirToTrackdir(Track track, DiagDirection diagdir)
Maps a track and an (4-way) dir to the trackdir that represents the track with the entry in the given...
Definition: track_func.h:486
TrackBits DiagdirReachesTracks(DiagDirection diagdir)
Returns all tracks that can be reached when entering a tile from a given (diagonal) direction.
Definition: track_func.h:573
TrackBits DiagDirToDiagTrackBits(DiagDirection diagdir)
Maps a (4-way) direction to the diagonal track bits incidating with that diagdir.
Definition: track_func.h:524
Trackdir DiagDirToDiagTrackdir(DiagDirection diagdir)
Maps a (4-way) direction to the diagonal trackdir that runs in that direction.
Definition: track_func.h:537
TrackdirBits TrackStatusToRedSignals(TrackStatus ts)
Returns the red-signal-information of a TrackStatus.
Definition: track_func.h:376
DiagDirection TrackdirToExitdir(Trackdir trackdir)
Maps a trackdir to the (4-way) direction the tile is exited when following that trackdir.
Definition: track_func.h:439
Track DiagDirToDiagTrack(DiagDirection diagdir)
Maps a (4-way) direction to the diagonal track incidating with that diagdir.
Definition: track_func.h:512
TrackBits TrackdirBitsToTrackBits(TrackdirBits bits)
Discards all directional information from a TrackdirBits value.
Definition: track_func.h:308
TrackBits
Allow incrementing of Track variables.
Definition: track_type.h:35
@ TRACK_BIT_WORMHOLE
Bitflag for a wormhole (used for tunnels)
Definition: track_type.h:52
@ TRACK_BIT_UPPER
Upper track.
Definition: track_type.h:39
@ TRACK_BIT_DEPOT
Bitflag for a depot.
Definition: track_type.h:53
@ TRACK_BIT_LEFT
Left track.
Definition: track_type.h:41
@ TRACK_BIT_Y
Y-axis track.
Definition: track_type.h:38
@ TRACK_BIT_NONE
No track.
Definition: track_type.h:36
@ TRACK_BIT_X
X-axis track.
Definition: track_type.h:37
@ TRACK_BIT_MASK
Bitmask for the first 6 bits.
Definition: track_type.h:51
@ TRACK_BIT_LOWER
Lower track.
Definition: track_type.h:40
@ TRACK_BIT_RIGHT
Right track.
Definition: track_type.h:42
Trackdir
Enumeration for tracks and directions.
Definition: track_type.h:67
@ INVALID_TRACKDIR
Flag for an invalid trackdir.
Definition: track_type.h:86
TrackdirBits
Allow incrementing of Trackdir variables.
Definition: track_type.h:98
@ TRACKDIR_BIT_NONE
No track build.
Definition: track_type.h:99
Track
These are used to specify a single track.
Definition: track_type.h:19
@ INVALID_TRACK
Flag for an invalid track.
Definition: track_type.h:28
@ TRACK_Y
Track along the y-axis (north-west to south-east)
Definition: track_type.h:22
@ TRACK_BEGIN
Used for iterations.
Definition: track_type.h:20
@ TRACK_X
Track along the x-axis (north-east to south-west)
Definition: track_type.h:21
@ VRF_POWEREDWAGON
Wagon is powered.
Definition: train.h:27
@ VRF_LEAVING_STATION
Train is just leaving a station.
Definition: train.h:33
@ VRF_TOGGLE_REVERSE
Used for vehicle var 0xFE bit 8 (toggled each time the train is reversed, accurate for first vehicle ...
Definition: train.h:31
@ VRF_REVERSE_DIRECTION
Reverse the visible direction of the vehicle.
Definition: train.h:28
@ VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL
Electric train engine is allowed to run on normal rail. *‍/.
Definition: train.h:30
@ VRF_TRAIN_STUCK
Train can't get a path reservation.
Definition: train.h:32
ConsistChangeFlags
Flags for Train::ConsistChanged.
Definition: train.h:44
@ CCF_CAPACITY
Allow vehicles to change capacity.
Definition: train.h:46
@ CCF_ARRANGE
Valid changes for arranging the consist in a depot.
Definition: train.h:52
@ CCF_LENGTH
Allow vehicles to change length.
Definition: train.h:45
@ CCF_TRACK
Valid changes while vehicle is driving, and possibly changing tracks.
Definition: train.h:48
@ TFP_SIGNAL
Ignore next signal, after the signal ignore being stuck.
Definition: train.h:40
@ TFP_NONE
Normal operation.
Definition: train.h:38
@ TFP_STUCK
Proceed till next signal, but ignore being stuck till then. This includes force leaving depots.
Definition: train.h:39
static void AffectSpeedByZChange(Train *v, int old_z)
Modify the speed of the vehicle due to a change in altitude.
Definition: train_cmd.cpp:3059
CommandCost CmdBuildRailVehicle(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **ret)
Build a railroad vehicle.
Definition: train_cmd.cpp:750
static void NormaliseTrainHead(Train *head)
Normalise the head of the train again, i.e.
Definition: train_cmd.cpp:1163
static CommandCost ValidateTrains(Train *original_dst, Train *dst, Train *original_src, Train *src, bool check_limit)
Validate whether we are going to create valid trains.
Definition: train_cmd.cpp:1102
static bool CheckTrainStayInDepot(Train *v)
Will the train stay in the depot the next tick?
Definition: train_cmd.cpp:2263
static FindDepotData FindClosestTrainDepot(Train *v, int max_distance)
Try to find a depot nearby.
Definition: train_cmd.cpp:2166
void UpdateLevelCrossing(TileIndex tile, bool sound, bool force_bar)
Update a level crossing to barred or open (crossing may include multiple adjacent tiles).
Definition: train_cmd.cpp:1773
static Vehicle * CollectTrackbitsFromCrashedVehiclesEnum(Vehicle *v, void *data)
Collect trackbits of all crashed train vehicles on a tile.
Definition: train_cmd.cpp:3599
static void MakeTrainBackup(TrainList &list, Train *t)
Make a backup of a train into a train list.
Definition: train_cmd.cpp:852
static void CheckNextTrainTile(Train *v)
Check if the train is on the last reserved tile and try to extend the path then.
Definition: train_cmd.cpp:2201
static void ArrangeTrains(Train **dst_head, Train *dst, Train **src_head, Train *src, bool move_chain)
Arrange the trains in the wanted way.
Definition: train_cmd.cpp:1122
bool TryPathReserve(Train *v, bool mark_as_stuck, bool first_tile_okay)
Try to reserve a path to a safe position.
Definition: train_cmd.cpp:2866
static bool TryReserveSafeTrack(const Train *v, TileIndex tile, Trackdir td, bool override_railtype)
Try to reserve any path to a safe tile, ignoring the vehicle's destination.
Definition: train_cmd.cpp:2593
static const uint16_t _breakdown_speeds[16]
Maximum speeds for train that is broken down or approaching line end.
Definition: train_cmd.cpp:3774
static bool TrainApproachingLineEnd(Train *v, bool signal, bool reverse)
Train is approaching line end, slow down and possibly reverse.
Definition: train_cmd.cpp:3787
static bool CheckTrainCollision(Train *v)
Checks whether the specified train has a collision with another vehicle.
Definition: train_cmd.cpp:3226
static void InsertInConsist(Train *dst, Train *chain)
Inserts a chain into the train at dst.
Definition: train_cmd.cpp:901
void UpdateAdjacentLevelCrossingTilesOnLevelCrossingRemoval(TileIndex tile, Axis road_axis)
Update adjacent level crossing tiles in this multi-track crossing, due to removal of a level crossing...
Definition: train_cmd.cpp:1822
static void SwapTrainFlags(uint16_t *swap_flag1, uint16_t *swap_flag2)
Swap the two up/down flags in two ways:
Definition: train_cmd.cpp:1565
CommandCost CmdMoveRailVehicle(DoCommandFlag flags, VehicleID src_veh, VehicleID dest_veh, bool move_chain)
Move a rail vehicle around inside the depot.
Definition: train_cmd.cpp:1193
static void UpdateLevelCrossingTile(TileIndex tile, bool sound, bool force_barred)
Sets a level crossing tile to the correct state.
Definition: train_cmd.cpp:1751
static Vehicle * TrainOnTileEnum(Vehicle *v, void *)
Check if the vehicle is a train.
Definition: train_cmd.cpp:1672
static bool HandleCrashedTrain(Train *v)
Handle a crashed train.
Definition: train_cmd.cpp:3735
void NormalizeTrainVehInDepot(const Train *u)
Move all free vehicles in the depot to the train.
Definition: train_cmd.cpp:693
static bool CheckLevelCrossing(TileIndex tile)
Check if a level crossing should be barred.
Definition: train_cmd.cpp:1738
uint8_t FreightWagonMult(CargoID cargo)
Return the cargo weight multiplier to use for a rail vehicle.
Definition: train_cmd.cpp:69
static CommandCost CheckNewTrain(Train *original_dst, Train *dst, Train *original_src, Train *src)
Check/validate whether we may actually build a new train.
Definition: train_cmd.cpp:969
static void AdvanceWagonsBeforeSwap(Train *v)
Advances wagons for train reversing, needed for variable length wagons.
Definition: train_cmd.cpp:1874
static void AdvanceWagonsAfterSwap(Train *v)
Advances wagons for train reversing, needed for variable length wagons.
Definition: train_cmd.cpp:1902
static bool TrainCheckIfLineEnds(Train *v, bool reverse=true)
Checks for line end.
Definition: train_cmd.cpp:3889
void ReverseTrainDirection(Train *v)
Turn a train around.
Definition: train_cmd.cpp:1967
void FreeTrainTrackReservation(const Train *v)
Free the reserved path in front of a vehicle.
Definition: train_cmd.cpp:2386
CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, bool sell_chain, bool backup_order, ClientID user)
Sell a (single) train wagon/engine.
Definition: train_cmd.cpp:1391
static uint TrainCrashed(Train *v)
Marks train as crashed and creates an AI event.
Definition: train_cmd.cpp:3149
static void NormaliseDualHeads(Train *t)
Normalise the dual heads in the train, i.e.
Definition: train_cmd.cpp:915
static CommandCost CheckTrainAttachment(Train *t)
Check whether the train parts can be attached.
Definition: train_cmd.cpp:993
static const AccelerationSlowdownParams _accel_slowdown[]
Speed update fractions for each acceleration type.
Definition: train_cmd.cpp:3047
static Track DoTrainPathfind(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool do_track_reservation, PBSTileInfo *dest, TileIndex *final_dest)
Perform pathfinding for a train.
Definition: train_cmd.cpp:2469
static CommandCost CmdBuildRailWagon(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **ret)
Build a railroad wagon.
Definition: train_cmd.cpp:616
CommandCost CmdForceTrainProceed(DoCommandFlag flags, VehicleID veh_id)
Force a train through a red signal.
Definition: train_cmd.cpp:2132
static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_dir)
Clear the reservation of tile that was just left by a wagon on track_dir.
Definition: train_cmd.cpp:2345
void CheckTrainsLengths()
Checks if lengths of all rail vehicles are valid.
Definition: train_cmd.cpp:76
static void MaybeBarCrossingWithSound(TileIndex tile)
Bars crossing and plays ding-ding sound if not barred already.
Definition: train_cmd.cpp:1860
bool TrainOnCrossing(TileIndex tile)
Check if a level crossing tile has a train on it.
Definition: train_cmd.cpp:1683
static void ChangeTrainDirRandomly(Train *v)
Rotate all vehicles of a (crashed) train chain randomly to animate the crash.
Definition: train_cmd.cpp:3707
void MarkDirtyAdjacentLevelCrossingTiles(TileIndex tile, Axis road_axis)
Find adjacent level crossing tiles in this multi-track crossing and mark them dirty.
Definition: train_cmd.cpp:1805
static Vehicle * FindTrainCollideEnum(Vehicle *v, void *data)
Collision test function.
Definition: train_cmd.cpp:3179
static void NormaliseSubtypes(Train *chain)
Normalise the sub types of the parts in this chain.
Definition: train_cmd.cpp:937
bool TrainController(Train *v, Vehicle *nomove, bool reverse=true)
Move a vehicle chain one movement stop forwards.
Definition: train_cmd.cpp:3278
static TileIndex TrainApproachingCrossingTile(const Train *v)
Determines whether train is approaching a rail-road crossing (thus making it barred)
Definition: train_cmd.cpp:3862
static void RemoveFromConsist(Train *part, bool chain=false)
Remove the given wagon from its consist.
Definition: train_cmd.cpp:884
static void RestoreTrainBackup(TrainList &list)
Restore the train from the backup list.
Definition: train_cmd.cpp:861
static void DeleteLastWagon(Train *v)
Deletes/Clears the last wagon of a crashed train.
Definition: train_cmd.cpp:3637
static bool TrainCanLeaveTile(const Train *v)
Determines whether train would like to leave the tile.
Definition: train_cmd.cpp:3832
int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, int *station_ahead, int *station_length)
Get the stop location of (the center) of the front vehicle of a train at a platform of a station.
Definition: train_cmd.cpp:263
static Vehicle * TrainApproachingCrossingEnum(Vehicle *v, void *data)
Checks if a train is approaching a rail-road crossing.
Definition: train_cmd.cpp:1697
static void TrainEnterStation(Train *v, StationID station)
Trains enters a station, send out a news item if it is the first train, and start loading.
Definition: train_cmd.cpp:3003
static void MarkTrainAsStuck(Train *v)
Mark a train as stuck and stop it if it isn't stopped right now.
Definition: train_cmd.cpp:1541
static bool TrainApproachingCrossing(TileIndex tile)
Finds a vehicle approaching rail-road crossing.
Definition: train_cmd.cpp:1718
void ReverseTrainSwapVeh(Train *v, int l, int r)
Swap vehicles l and r in consist v, and reverse their direction.
Definition: train_cmd.cpp:1630
static PBSTileInfo ExtendTrainReservation(const Train *v, TrackBits *new_tracks, DiagDirection *enterdir)
Extend a train path as far as possible.
Definition: train_cmd.cpp:2480
void GetTrainSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type)
Get the size of the sprite of a train sprite heading west, or both heads (used for lists).
Definition: train_cmd.cpp:581
static void CheckIfTrainNeedsService(Train *v)
Check whether a train needs service, and if so, find a depot or service it.
Definition: train_cmd.cpp:4138
std::vector< Train * > TrainList
Helper type for lists/vectors of trains.
Definition: train_cmd.cpp:845
static void UpdateStatusAfterSwap(Train *v)
Updates some variables after swapping the vehicle.
Definition: train_cmd.cpp:1593
CommandCost CmdReverseTrainDirection(DoCommandFlag flags, VehicleID veh_id, bool reverse_single_veh)
Reverse train.
Definition: train_cmd.cpp:2059
Command definitions related to trains.
Sprites to use for trains.
@ TRANSPORT_RAIL
Transport by train.
bool IsTunnel(Tile t)
Is this a tunnel (entrance)?
Definition: tunnel_map.h:23
void MarkBridgeDirty(TileIndex begin, TileIndex end, DiagDirection direction, uint bridge_height)
Mark bridge tiles dirty.
DiagDirection GetTunnelBridgeDirection(Tile t)
Get the direction pointing to the other end.
TileIndex GetOtherTunnelBridgeEnd(Tile t)
Determines type of the wormhole and returns its other end.
void SetTunnelBridgeReservation(Tile t, bool b)
Set the reservation state of the rail tunnel/bridge.
void VehicleEnterDepot(Vehicle *v)
Vehicle entirely entered the depot, update its status, orders, vehicle windows, service it,...
Definition: vehicle.cpp:1552
UnitID GetFreeUnitNumber(VehicleType type)
Get an unused unit number for a vehicle (if allowed).
Definition: vehicle.cpp:1895
void VehicleLengthChanged(const Vehicle *u)
Logs a bug in GRF and shows a warning message if this is for the first time this happened.
Definition: vehicle.cpp:346
void VehicleServiceInDepot(Vehicle *v)
Service a vehicle and all subsequent vehicles in the consist.
Definition: vehicle.cpp:167
void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc)
Find a vehicle from a specific location.
Definition: vehicle.cpp:445
GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
Get position information of a vehicle when moving one pixel in the direction it is facing.
Definition: vehicle.cpp:1784
bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
Checks whether a vehicle is on a specific location.
Definition: vehicle.cpp:520
void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
Find a vehicle from a specific location.
Definition: vehicle.cpp:505
void DecreaseVehicleValue(Vehicle *v)
Decrease the value of a vehicle.
Definition: vehicle.cpp:1301
void EconomyAgeVehicle(Vehicle *v)
Update economy age of a vehicle.
Definition: vehicle.cpp:1429
CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore)
Finds vehicle in tunnel / bridge.
Definition: vehicle.cpp:575
void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical)
Displays a "NewGrf Bug" error message for a engine, and pauses the game if not networking.
Definition: vehicle.cpp:317
void AgeVehicle(Vehicle *v)
Update age of a vehicle.
Definition: vehicle.cpp:1441
@ VF_BUILT_AS_PROTOTYPE
Vehicle is a prototype (accepted as exclusive preview).
Definition: vehicle_base.h:47
@ VS_TRAIN_SLOWING
Train is slowing down.
Definition: vehicle_base.h:37
@ VS_STOPPED
Vehicle is stopped by the player.
Definition: vehicle_base.h:34
@ VS_HIDDEN
Vehicle is not visible.
Definition: vehicle_base.h:33
@ VS_CRASHED
Vehicle is crashed.
Definition: vehicle_base.h:40
@ VS_DEFPAL
Use default vehicle palette.
Definition: vehicle_base.h:36
@ VE_DISABLE_WAGON_POWER
Flag to disable wagon power.
Definition: vehicle_base.h:95
Functions related to vehicles.
@ VIWD_CONSIST_CHANGED
Vehicle composition was changed.
Definition: vehicle_gui.h:37
EngineImageType
Visualisation contexts of vehicles and engines.
Definition: vehicle_type.h:78
@ VEH_TRAIN
Train vehicle type.
Definition: vehicle_type.h:24
uint32_t VehicleID
The type all our vehicle IDs have.
Definition: vehicle_type.h:16
static const VehicleID INVALID_VEHICLE
Constant representing a non-existing vehicle.
Definition: vehicle_type.h:54
static const uint VEHICLE_LENGTH
The length of a vehicle in tile units.
Definition: vehicle_type.h:69
@ WID_VV_REFIT
Open the refit window.
@ WID_VV_START_STOP
Start or stop this vehicle, and show information about the current state.
Functions related to (drawing on) viewports.
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Definition: window.cpp:1140
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition: window.cpp:3119
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
Mark window data of the window of a given class and specific window number as invalid (in need of re-...
Definition: window.cpp:3211
void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, WidgetID widget_index)
Mark a particular widget in a particular window as dirty (in need of repainting)
Definition: window.cpp:3106
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition: window.cpp:3093
void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope)
Mark window data of all windows of a given class as invalid (in need of re-computing) Note that by de...
Definition: window.cpp:3228
@ WC_VEHICLE_ORDERS
Vehicle orders; Window numbers:
Definition: window_type.h:212
@ WC_VEHICLE_DEPOT
Depot view; Window numbers:
Definition: window_type.h:351
@ WC_TRAINS_LIST
Trains list; Window numbers:
Definition: window_type.h:308
@ WC_VEHICLE_REFIT
Vehicle refit; Window numbers:
Definition: window_type.h:206
@ WC_VEHICLE_DETAILS
Vehicle details; Window numbers:
Definition: window_type.h:200
@ WC_COMPANY
Company view; Window numbers:
Definition: window_type.h:369
@ WC_VEHICLE_VIEW
Vehicle view; Window numbers:
Definition: window_type.h:339
@ WC_VEHICLE_TIMETABLE
Vehicle timetable; Window numbers:
Definition: window_type.h:224
FindDepotData YapfTrainFindNearestDepot(const Train *v, int max_distance)
Used when user sends train to the nearest depot or if train needs servicing using YAPF.
Definition: yapf_rail.cpp:612
bool YapfTrainFindNearestSafeTile(const Train *v, TileIndex tile, Trackdir td, bool override_railtype)
Try to extend the reserved path of a train to the nearest safe tile using YAPF.
Definition: yapf_rail.cpp:625
bool YapfTrainCheckReverse(const Train *v)
Returns true if it is better to reverse the train before leaving station using YAPF.
Definition: yapf_rail.cpp:559
Track YapfTrainChooseTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool reserve_track, struct PBSTileInfo *target, TileIndex *dest)
Finds the best path for given train using YAPF.
Definition: yapf_rail.cpp:550
Base includes/functions for YAPF.
Functions related to zooming.
int ScaleSpriteTrad(int value)
Scale traditional pixel dimensions to GUI zoom level, for drawing sprites.
Definition: zoom_func.h:107
int UnScaleGUI(int value)
Short-hand to apply GUI zoom level.
Definition: zoom_func.h:77