OpenTTD Source 20260208-master-g43af8e94d0
roadveh_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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "stdafx.h"
11#include "roadveh.h"
12#include "command_func.h"
13#include "error_func.h"
14#include "news_func.h"
15#include "station_base.h"
16#include "company_func.h"
18#include "newgrf_sound.h"
20#include "strings_func.h"
21#include "tunnelbridge_map.h"
24#include "vehicle_func.h"
25#include "sound_func.h"
26#include "ai/ai.hpp"
27#include "game/game.hpp"
28#include "depot_map.h"
29#include "effectvehicle_func.h"
30#include "roadstop_base.h"
31#include "core/random_func.hpp"
32#include "company_base.h"
33#include "core/backup_type.hpp"
34#include "newgrf.h"
35#include "zoom_func.h"
36#include "framerate_type.h"
37#include "roadveh_cmd.h"
38#include "road_cmd.h"
39#include "newgrf_roadstop.h"
40
41#include "table/strings.h"
42
43#include "safeguards.h"
44
45static const uint16_t _roadveh_images[] = {
46 0xCD4, 0xCDC, 0xCE4, 0xCEC, 0xCF4, 0xCFC, 0xD0C, 0xD14,
47 0xD24, 0xD1C, 0xD2C, 0xD04, 0xD1C, 0xD24, 0xD6C, 0xD74,
48 0xD7C, 0xC14, 0xC1C, 0xC24, 0xC2C, 0xC34, 0xC3C, 0xC4C,
49 0xC54, 0xC64, 0xC5C, 0xC6C, 0xC44, 0xC5C, 0xC64, 0xCAC,
50 0xCB4, 0xCBC, 0xD94, 0xD9C, 0xDA4, 0xDAC, 0xDB4, 0xDBC,
51 0xDCC, 0xDD4, 0xDE4, 0xDDC, 0xDEC, 0xDC4, 0xDDC, 0xDE4,
52 0xE2C, 0xE34, 0xE3C, 0xC14, 0xC1C, 0xC2C, 0xC3C, 0xC4C,
53 0xC5C, 0xC64, 0xC6C, 0xC74, 0xC84, 0xC94, 0xCA4
54};
55
56static const uint16_t _roadveh_full_adder[] = {
57 0, 88, 0, 0, 0, 0, 48, 48,
58 48, 48, 0, 0, 64, 64, 0, 16,
59 16, 0, 88, 0, 0, 0, 0, 48,
60 48, 48, 48, 0, 0, 64, 64, 0,
61 16, 16, 0, 88, 0, 0, 0, 0,
62 48, 48, 48, 48, 0, 0, 64, 64,
63 0, 16, 16, 0, 8, 8, 8, 8,
64 0, 0, 0, 8, 8, 8, 8
65};
66static_assert(lengthof(_roadveh_images) == lengthof(_roadveh_full_adder));
67
68template <>
69bool IsValidImageIndex<VEH_ROAD>(uint8_t image_index)
70{
71 return image_index < lengthof(_roadveh_images);
72}
73
74static const Trackdir _road_reverse_table[DIAGDIR_END] = {
76};
77
83{
84 assert(this->IsFrontEngine());
86}
87
94{
95 int reference_width = ROADVEHINFO_DEFAULT_VEHICLE_WIDTH;
96
97 if (offset != nullptr) {
98 offset->x = ScaleSpriteTrad(reference_width) / 2;
99 offset->y = 0;
100 }
101 return ScaleSpriteTrad(this->gcache.cached_veh_length * reference_width / VEHICLE_LENGTH);
102}
103
104static void GetRoadVehIcon(EngineID engine, EngineImageType image_type, VehicleSpriteSeq *result)
105{
106 const Engine *e = Engine::Get(engine);
107 uint8_t spritenum = e->VehInfo<RoadVehicleInfo>().image_index;
108
109 if (IsCustomVehicleSpriteNum(spritenum)) {
110 GetCustomVehicleIcon(engine, DIR_W, image_type, result);
111 if (result->IsValid()) return;
112
113 spritenum = e->original_image_index;
114 }
115
116 assert(IsValidImageIndex<VEH_ROAD>(spritenum));
117 result->Set(DIR_W + _roadveh_images[spritenum]);
118}
119
121{
122 uint8_t spritenum = this->spritenum;
123
124 if (IsCustomVehicleSpriteNum(spritenum)) {
126 GetCustomVehicleSprite(this, direction, image_type, result);
127 if (result->IsValid()) return;
128
130 }
131
133 SpriteID sprite = direction + _roadveh_images[spritenum];
134
135 if (this->cargo.StoredCount() >= this->cargo_cap / 2U) sprite += _roadveh_full_adder[spritenum];
136
137 result->Set(sprite);
138}
139
150void DrawRoadVehEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type)
151{
153 GetRoadVehIcon(engine, image_type, &seq);
154
155 Rect rect;
156 seq.GetBounds(&rect);
157 preferred_x = Clamp(preferred_x,
158 left - UnScaleGUI(rect.left),
159 right - UnScaleGUI(rect.right));
160
161 seq.Draw(preferred_x, y, pal, pal == PALETTE_CRASH);
162}
163
173void GetRoadVehSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type)
174{
176 GetRoadVehIcon(engine, image_type, &seq);
177
178 Rect rect;
179 seq.GetBounds(&rect);
180
181 width = UnScaleGUI(rect.Width());
182 height = UnScaleGUI(rect.Height());
183 xoffs = UnScaleGUI(rect.left);
184 yoffs = UnScaleGUI(rect.top);
185}
186
192static uint GetRoadVehLength(const RoadVehicle *v)
193{
194 const Engine *e = v->GetEngine();
195 uint length = VEHICLE_LENGTH;
196
197 uint16_t veh_len = CALLBACK_FAILED;
198 if (e->GetGRF() != nullptr && e->GetGRF()->grf_version >= 8) {
199 /* Use callback 36 */
200 veh_len = GetVehicleProperty(v, PROP_ROADVEH_SHORTEN_FACTOR, CALLBACK_FAILED);
201 if (veh_len != CALLBACK_FAILED && veh_len >= VEHICLE_LENGTH) ErrorUnknownCallbackResult(e->GetGRFID(), CBID_VEHICLE_LENGTH, veh_len);
202 } else {
203 /* Use callback 11 */
204 veh_len = GetVehicleCallback(CBID_VEHICLE_LENGTH, 0, 0, v->engine_type, v);
205 }
206 if (veh_len == CALLBACK_FAILED) veh_len = e->VehInfo<RoadVehicleInfo>().shorten_factor;
207 if (veh_len != 0) {
208 length -= Clamp(veh_len, 0, VEHICLE_LENGTH - 1);
209 }
210
211 return length;
212}
213
220void RoadVehUpdateCache(RoadVehicle *v, bool same_length)
221{
222 assert(v->type == VEH_ROAD);
223 assert(v->IsFrontEngine());
224
226
228
229 for (RoadVehicle *u = v; u != nullptr; u = u->Next()) {
230 /* Check the v->first cache. */
231 assert(u->First() == v);
232
233 /* Update the 'first engine' */
234 u->gcache.first_engine = (v == u) ? EngineID::Invalid() : v->engine_type;
235
236 /* Update the length of the vehicle. */
237 uint veh_len = GetRoadVehLength(u);
238 /* Verify length hasn't changed. */
239 if (same_length && veh_len != u->gcache.cached_veh_length) VehicleLengthChanged(u);
240
241 u->gcache.cached_veh_length = veh_len;
242 v->gcache.cached_total_length += u->gcache.cached_veh_length;
243
244 /* Update visual effect */
245 u->UpdateVisualEffect();
246
247 /* Update cargo aging period. */
248 u->vcache.cached_cargo_age_period = GetVehicleProperty(u, PROP_ROADVEH_CARGO_AGE_PERIOD, EngInfo(u->engine_type)->cargo_age_period);
249 }
250
251 uint max_speed = GetVehicleProperty(v, PROP_ROADVEH_SPEED, 0);
252 v->vcache.cached_max_speed = (max_speed != 0) ? max_speed * 4 : RoadVehInfo(v->engine_type)->max_speed;
253}
254
263CommandCost CmdBuildRoadVehicle(DoCommandFlags flags, TileIndex tile, const Engine *e, Vehicle **ret)
264{
265 /* Check that the vehicle can drive on the road in question */
266 RoadType rt = e->VehInfo<RoadVehicleInfo>().roadtype;
267 const RoadTypeInfo *rti = GetRoadTypeInfo(rt);
268 if (!HasTileAnyRoadType(tile, rti->powered_roadtypes)) return CommandCost(STR_ERROR_DEPOT_WRONG_DEPOT_TYPE);
269
270 if (flags.Test(DoCommandFlag::Execute)) {
271 const RoadVehicleInfo *rvi = &e->VehInfo<RoadVehicleInfo>();
272
274 *ret = v;
276 v->owner = _current_company;
277
278 v->tile = tile;
279 int x = TileX(tile) * TILE_SIZE + TILE_SIZE / 2;
280 int y = TileY(tile) * TILE_SIZE + TILE_SIZE / 2;
281 v->x_pos = x;
282 v->y_pos = y;
283 v->z_pos = GetSlopePixelZ(x, y, true);
284
285 v->state = RVSB_IN_DEPOT;
287
288 v->spritenum = rvi->image_index;
289 v->cargo_type = e->GetDefaultCargoType();
290 assert(IsValidCargoType(v->cargo_type));
291 v->cargo_cap = rvi->capacity;
292 v->refit_cap = 0;
293
294 v->last_station_visited = StationID::Invalid();
295 v->last_loading_station = StationID::Invalid();
296 v->engine_type = e->index;
297 v->gcache.first_engine = EngineID::Invalid(); // needs to be set before first callback
298
299 v->reliability = e->reliability;
300 v->reliability_spd_dec = e->reliability_spd_dec;
301 v->max_age = e->GetLifeLengthInDays();
302
303 v->SetServiceInterval(Company::Get(v->owner)->settings.vehicle.servint_roadveh);
304
305 v->date_of_last_service = TimerGameEconomy::date;
306 v->date_of_last_service_newgrf = TimerGameCalendar::date;
307 v->build_year = TimerGameCalendar::year;
308
309 v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
310 v->random_bits = Random();
311 v->SetFrontEngine();
312
313 v->roadtype = rt;
314 v->compatible_roadtypes = rti->powered_roadtypes;
315 v->gcache.cached_veh_length = VEHICLE_LENGTH;
316
318 v->SetServiceIntervalIsPercent(Company::Get(_current_company)->settings.vehicle.servint_ispercent);
319
321 v->InvalidateNewGRFCacheOfChain();
322
323 /* Call various callbacks after the whole consist has been constructed */
324 for (RoadVehicle *u = v; u != nullptr; u = u->Next()) {
325 u->cargo_cap = u->GetEngine()->DetermineCapacity(u);
326 u->refit_cap = 0;
327 v->InvalidateNewGRFCache();
328 u->InvalidateNewGRFCache();
329 }
331 /* Initialize cached values for realistic acceleration. */
332 if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) v->CargoChanged();
333
334 v->UpdatePosition();
335
337 }
338
339 return CommandCost();
340}
341
342static FindDepotData FindClosestRoadDepot(const RoadVehicle *v, int max_distance)
343{
344 if (IsRoadDepotTile(v->tile)) return FindDepotData(v->tile, 0);
345
346 return YapfRoadVehicleFindNearestDepot(v, max_distance);
347}
348
350{
351 FindDepotData rfdd = FindClosestRoadDepot(this, 0);
352 if (rfdd.best_length == UINT_MAX) return ClosestDepot();
353
354 return ClosestDepot(rfdd.tile, GetDepotIndex(rfdd.tile));
355}
356
363CommandCost CmdTurnRoadVeh(DoCommandFlags flags, VehicleID veh_id)
364{
366 if (v == nullptr) return CMD_ERROR;
367
368 if (!v->IsPrimaryVehicle()) return CMD_ERROR;
369
371 if (ret.Failed()) return ret;
372
373 if (v->vehstatus.Any({VehState::Stopped, VehState::Crashed}) ||
374 v->breakdown_ctr != 0 ||
375 v->overtaking != 0 ||
376 v->state == RVSB_WORMHOLE ||
377 v->IsInDepot() ||
378 v->current_order.IsType(OT_LOADING)) {
379 return CMD_ERROR;
380 }
381
383
385
386 if (flags.Test(DoCommandFlag::Execute)) {
387 v->reverse_ctr = 180;
388
389 /* Unbunching data is no longer valid. */
391 }
392
393 return CommandCost();
394}
395
396
398{
399 for (RoadVehicle *v = this; v != nullptr; v = v->Next()) {
400 v->colourmap = PAL_NONE;
401 v->UpdateViewport(true, false);
402 }
403 this->CargoChanged();
404}
405
407{
408 /* Set common defaults. */
409 this->bounds = {{-1, -1, 0}, {3, 3, 6}, {}};
410
411 if (!IsDiagonalDirection(this->direction)) {
412 static const Point _sign_table[] = {
413 /* x, y */
414 {-1, -1}, // DIR_N
415 {-1, 1}, // DIR_E
416 { 1, 1}, // DIR_S
417 { 1, -1}, // DIR_W
418 };
419
420 int half_shorten = (VEHICLE_LENGTH - this->gcache.cached_veh_length) / 2;
421
422 /* For all straight directions, move the bound box to the centre of the vehicle, but keep the size. */
423 this->bounds.offset.x -= half_shorten * _sign_table[DirToDiagDir(this->direction)].x;
424 this->bounds.offset.y -= half_shorten * _sign_table[DirToDiagDir(this->direction)].y;
425 } else {
426 /* Unlike trains, road vehicles do not have their offsets moved to the centre. */
427 switch (this->direction) {
428 /* Shorten southern corner of the bounding box according the vehicle length. */
429 case DIR_NE:
430 this->bounds.origin.x = -3;
431 this->bounds.extent.x = this->gcache.cached_veh_length;
432 this->bounds.offset.x = 1;
433 break;
434
435 case DIR_NW:
436 this->bounds.origin.y = -3;
437 this->bounds.extent.y = this->gcache.cached_veh_length;
438 this->bounds.offset.y = 1;
439 break;
440
441 /* Move northern corner of the bounding box down according to vehicle length. */
442 case DIR_SW:
443 this->bounds.origin.x = -3 + (VEHICLE_LENGTH - this->gcache.cached_veh_length);
444 this->bounds.extent.x = this->gcache.cached_veh_length;
445 this->bounds.offset.x = 1 - (VEHICLE_LENGTH - this->gcache.cached_veh_length);
446 break;
447
448 case DIR_SE:
449 this->bounds.origin.y = -3 + (VEHICLE_LENGTH - this->gcache.cached_veh_length);
450 this->bounds.extent.y = this->gcache.cached_veh_length;
451 this->bounds.offset.y = 1 - (VEHICLE_LENGTH - this->gcache.cached_veh_length);
452 break;
453
454 default:
455 NOT_REACHED();
456 }
457 }
458}
459
465{
466 int max_speed = this->gcache.cached_max_track_speed;
467
468 /* Limit speed to 50% while reversing, 75% in curves. */
469 for (const RoadVehicle *u = this; u != nullptr; u = u->Next()) {
470 if (_settings_game.vehicle.roadveh_acceleration_model == AM_REALISTIC) {
472 max_speed = this->gcache.cached_max_track_speed / 2;
473 break;
474 } else if ((u->direction & 1) == 0) {
475 max_speed = this->gcache.cached_max_track_speed * 3 / 4;
476 }
477 }
478
479 /* Vehicle is on the middle part of a bridge. */
480 if (u->state == RVSB_WORMHOLE && !u->vehstatus.Test(VehState::Hidden)) {
481 max_speed = std::min(max_speed, GetBridgeSpec(GetBridgeType(u->tile))->speed * 2);
482 }
483 }
484
485 return std::min(max_speed, this->current_order.GetMaxSpeed() * 2);
486}
487
493{
494 RoadVehicle *first = v->First();
495 Vehicle *u = v;
496 for (; v->Next() != nullptr; v = v->Next()) u = v;
497 u->SetNext(nullptr);
498 v->last_station_visited = first->last_station_visited; // for PreDestructor
499
500 /* Only leave the road stop when we're really gone. */
501 if (IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
502
503 delete v;
504}
505
506static void RoadVehSetRandomDirection(RoadVehicle *v)
507{
508 static const DirDiff delta[] = {
510 };
511
512 do {
513 uint32_t r = Random();
514
515 v->direction = ChangeDir(v->direction, delta[r & 3]);
516 v->UpdateViewport(true, true);
517 } while ((v = v->Next()) != nullptr);
518}
519
526{
527 v->crashed_ctr++;
528 if (v->crashed_ctr == 2) {
530 } else if (v->crashed_ctr <= 45) {
531 if ((v->tick_counter & 7) == 0) RoadVehSetRandomDirection(v);
532 } else if (v->crashed_ctr >= 2220 && !(v->tick_counter & 0x1F)) {
533 bool ret = v->Next() != nullptr;
535 return ret;
536 }
537
538 return true;
539}
540
541uint RoadVehicle::Crash(bool flooded)
542{
543 uint victims = this->GroundVehicleBase::Crash(flooded);
544 if (this->IsFrontEngine()) {
545 victims += 1; // driver
546
547 /* If we're in a drive through road stop we ought to leave it */
548 if (IsInsideMM(this->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
549 RoadStop::GetByTile(this->tile, GetRoadStopType(this->tile))->Leave(this);
550 }
551 }
552 this->crashed_ctr = flooded ? 2000 : 1; // max 2220, disappear pretty fast when flooded
553 return victims;
554}
555
556static void RoadVehCrash(RoadVehicle *v)
557{
558 uint victims = v->Crash();
559
560 AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING, victims, v->owner));
561 Game::NewEvent(new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING, victims, v->owner));
562
563 EncodedString headline = (victims == 1)
564 ? GetEncodedString(STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER)
565 : GetEncodedString(STR_NEWS_ROAD_VEHICLE_CRASH, victims);
567
568 AddTileNewsItem(std::move(headline), newstype, v->tile);
569
570 ModifyStationRatingAround(v->tile, v->owner, -160, 22);
571 if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, v);
572}
573
574static bool RoadVehCheckTrainCrash(RoadVehicle *v)
575{
576 for (RoadVehicle *u = v; u != nullptr; u = u->Next()) {
577 if (u->state == RVSB_WORMHOLE) continue;
578
579 TileIndex tile = u->tile;
580
581 if (!IsLevelCrossingTile(tile)) continue;
582
583 if (HasVehicleNearTileXY(v->x_pos, v->y_pos, 4, [&u](const Vehicle *t) {
584 return t->type == VEH_TRAIN && abs(t->z_pos - u->z_pos) <= 6;
585 })) {
586 RoadVehCrash(v);
587 return true;
588 }
589 }
590
591 return false;
592}
593
595{
596 if (station == this->last_station_visited) this->last_station_visited = StationID::Invalid();
597
598 const Station *st = Station::Get(station);
599 if (!CanVehicleUseStation(this, st)) {
600 /* There is no stop left at the station, so don't even TRY to go there */
602 return TileIndex{};
603 }
604
605 return st->xy;
606}
607
608static void StartRoadVehSound(const RoadVehicle *v)
609{
610 if (!PlayVehicleSound(v, VSE_START)) {
611 SoundID s = RoadVehInfo(v->engine_type)->sfx;
612 if (s == SND_19_DEPARTURE_OLD_RV_1 && (v->tick_counter & 3) == 0) {
614 }
615 SndPlayVehicleFx(s, v);
616 }
617}
618
620 int x;
621 int y;
622 const Vehicle *veh;
623 Vehicle *best;
624 uint best_diff;
625 Direction dir;
626};
627
628static void FindClosestBlockingRoadVeh(Vehicle *v, RoadVehFindData *rvf)
629{
630 static const int8_t dist_x[] = { -4, -8, -4, -1, 4, 8, 4, 1 };
631 static const int8_t dist_y[] = { -4, -1, 4, 8, 4, 1, -4, -8 };
632
633 int x_diff = v->x_pos - rvf->x;
634 int y_diff = v->y_pos - rvf->y;
635
636 /* Not a close Road vehicle when it's not a road vehicle, in the depot, or ourself. */
637 if (v->type != VEH_ROAD || v->IsInDepot() || rvf->veh->First() == v->First()) return;
638
639 /* Not close when at a different height or when going in a different direction. */
640 if (abs(v->z_pos - rvf->veh->z_pos) >= 6 || v->direction != rvf->dir) return;
641
642 /* We 'return' the closest vehicle, in distance and then VehicleID as tie-breaker. */
643 uint diff = abs(x_diff) + abs(y_diff);
644 if (diff > rvf->best_diff || (diff == rvf->best_diff && v->index > rvf->best->index)) return;
645
646 auto IsCloseOnAxis = [](int dist, int diff) {
647 if (dist < 0) return diff > dist && diff <= 0;
648 return diff < dist && diff >= 0;
649 };
650
651 if (IsCloseOnAxis(dist_x[v->direction], x_diff) && IsCloseOnAxis(dist_y[v->direction], y_diff)) {
652 rvf->best = v;
653 rvf->best_diff = diff;
654 }
655}
656
657static RoadVehicle *RoadVehFindCloseTo(RoadVehicle *v, int x, int y, Direction dir, bool update_blocked_ctr = true)
658{
659 RoadVehFindData rvf;
660 RoadVehicle *front = v->First();
661
662 if (front->reverse_ctr != 0) return nullptr;
663
664 rvf.x = x;
665 rvf.y = y;
666 rvf.dir = dir;
667 rvf.veh = v;
668 rvf.best_diff = UINT_MAX;
669
670 if (front->state == RVSB_WORMHOLE) {
671 for (Vehicle *u : VehiclesOnTile(v->tile)) {
672 FindClosestBlockingRoadVeh(u, &rvf);
673 }
675 FindClosestBlockingRoadVeh(u, &rvf);
676 }
677 } else {
678 for (Vehicle *u : VehiclesNearTileXY(x, y, 8)) {
679 FindClosestBlockingRoadVeh(u, &rvf);
680 }
681 }
682
683 /* This code protects a roadvehicle from being blocked for ever
684 * If more than 1480 / 74 days a road vehicle is blocked, it will
685 * drive just through it. The ultimate backup-code of TTD.
686 * It can be disabled. */
687 if (rvf.best_diff == UINT_MAX) {
688 front->blocked_ctr = 0;
689 return nullptr;
690 }
691
692 if (update_blocked_ctr && ++front->blocked_ctr > 1480) return nullptr;
693
694 return RoadVehicle::From(rvf.best);
695}
696
702static void RoadVehArrivesAt(const RoadVehicle *v, Station *st)
703{
704 if (v->IsBus()) {
705 /* Check if station was ever visited before */
706 if (!(st->had_vehicle_of_type & HVOT_BUS)) {
707 st->had_vehicle_of_type |= HVOT_BUS;
709 GetEncodedString(RoadTypeIsRoad(v->roadtype) ? STR_NEWS_FIRST_BUS_ARRIVAL : STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL, st->index),
711 v->index,
712 st->index
713 );
714 AI::NewEvent(v->owner, new ScriptEventStationFirstVehicle(st->index, v->index));
715 Game::NewEvent(new ScriptEventStationFirstVehicle(st->index, v->index));
716 }
717 } else {
718 /* Check if station was ever visited before */
719 if (!(st->had_vehicle_of_type & HVOT_TRUCK)) {
720 st->had_vehicle_of_type |= HVOT_TRUCK;
722 GetEncodedString(RoadTypeIsRoad(v->roadtype) ? STR_NEWS_FIRST_TRUCK_ARRIVAL : STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL, st->index),
724 v->index,
725 st->index
726 );
727 AI::NewEvent(v->owner, new ScriptEventStationFirstVehicle(st->index, v->index));
728 Game::NewEvent(new ScriptEventStationFirstVehicle(st->index, v->index));
729 }
730 }
731}
732
741{
742 switch (_settings_game.vehicle.roadveh_acceleration_model) {
743 default: NOT_REACHED();
744 case AM_ORIGINAL:
745 return this->DoUpdateSpeed(this->overtaking != 0 ? 512 : 256, 0, this->GetCurrentMaxSpeed());
746
747 case AM_REALISTIC:
748 return this->DoUpdateSpeed(this->GetAcceleration() + (this->overtaking != 0 ? 256 : 0), this->GetAccelerationStatus() == AS_BRAKE ? 0 : 4, this->GetCurrentMaxSpeed());
749 }
750}
751
752static Direction RoadVehGetNewDirection(const RoadVehicle *v, int x, int y)
753{
754 static const Direction _roadveh_new_dir[] = {
758 };
759
760 x = x - v->x_pos + 1;
761 y = y - v->y_pos + 1;
762
763 if ((uint)x > 2 || (uint)y > 2) return v->direction;
764 return _roadveh_new_dir[y * 4 + x];
765}
766
767static Direction RoadVehGetSlidingDirection(const RoadVehicle *v, int x, int y)
768{
769 Direction new_dir = RoadVehGetNewDirection(v, x, y);
770 Direction old_dir = v->direction;
771 DirDiff delta;
772
773 if (new_dir == old_dir) return old_dir;
774 delta = (DirDifference(new_dir, old_dir) > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
775 return ChangeDir(old_dir, delta);
776}
777
779 const RoadVehicle *u;
780 const RoadVehicle *v;
781 TileIndex tile;
782 Trackdir trackdir;
783};
784
792{
793 if (!HasTileAnyRoadType(od->tile, od->v->compatible_roadtypes)) return true;
794 TrackStatus ts = GetTileTrackStatus(od->tile, TRANSPORT_ROAD, GetRoadTramType(od->v->roadtype));
795 TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts);
796 TrackdirBits red_signals = TrackStatusToRedSignals(ts); // barred level crossing
797 TrackBits trackbits = TrackdirBitsToTrackBits(trackdirbits);
798
799 /* Track does not continue along overtaking direction || track has junction || levelcrossing is barred */
800 if (!HasBit(trackdirbits, od->trackdir) || (trackbits & ~TRACK_BIT_CROSS) || (red_signals != TRACKDIR_BIT_NONE)) return true;
801
802 /* Are there more vehicles on the tile except the two vehicles involved in overtaking */
803 return HasVehicleOnTile(od->tile, [&](const Vehicle *v) {
804 return v->type == VEH_ROAD && v->First() == v && v != od->u && v != od->v;
805 });
806}
807
808static void RoadVehCheckOvertake(RoadVehicle *v, RoadVehicle *u)
809{
810 OvertakeData od;
811
812 od.v = v;
813 od.u = u;
814
815 /* Trams can't overtake other trams */
816 if (RoadTypeIsTram(v->roadtype)) return;
817
818 /* Don't overtake in stations */
820
821 /* For now, articulated road vehicles can't overtake anything. */
822 if (v->HasArticulatedPart()) return;
823
824 /* Vehicles are not driving in same direction || direction is not a diagonal direction */
825 if (v->direction != u->direction || !(v->direction & 1)) return;
826
827 /* Check if vehicle is in a road stop, depot, tunnel or bridge or not on a straight road */
829
830 /* Can't overtake a vehicle that is moving faster than us. If the vehicle in front is
831 * accelerating, take the maximum speed for the comparison, else the current speed.
832 * Original acceleration always accelerates, so always use the maximum speed. */
833 int u_speed = (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL || u->GetAcceleration() > 0) ? u->GetCurrentMaxSpeed() : u->cur_speed;
834 if (u_speed >= v->GetCurrentMaxSpeed() &&
836 u->cur_speed != 0) {
837 return;
838 }
839
841
842 /* Are the current and the next tile suitable for overtaking?
843 * - Does the track continue along od.trackdir
844 * - No junctions
845 * - No barred levelcrossing
846 * - No other vehicles in the way
847 */
848 od.tile = v->tile;
849 if (CheckRoadBlockedForOvertaking(&od)) return;
850
851 od.tile = v->tile + TileOffsByDiagDir(DirToDiagDir(v->direction));
852 if (CheckRoadBlockedForOvertaking(&od)) return;
853
854 /* When the vehicle in front of us is stopped we may only take
855 * half the time to pass it than when the vehicle is moving. */
856 v->overtaking_ctr = (od.u->cur_speed == 0 || od.u->vehstatus.Test(VehState::Stopped)) ? RV_OVERTAKE_TIMEOUT / 2 : 0;
858}
859
860static void RoadZPosAffectSpeed(RoadVehicle *v, int old_z)
861{
862 if (old_z == v->z_pos || _settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) return;
863
864 if (old_z < v->z_pos) {
865 v->cur_speed = v->cur_speed * 232 / 256; // slow down by ~10%
866 } else {
867 uint16_t spd = v->cur_speed + 2;
868 if (spd <= v->gcache.cached_max_track_speed) v->cur_speed = spd;
869 }
870}
871
872static int PickRandomBit(uint bits)
873{
874 uint i;
875 uint num = RandomRange(CountBits(bits));
876
877 for (i = 0; !(bits & 1) || (int)--num >= 0; bits >>= 1, i++) {}
878 return i;
879}
880
890{
891#define return_track(x) { best_track = (Trackdir)x; goto found_best_track; }
892
893 Trackdir best_track;
894 bool path_found = true;
895
896 TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_ROAD, GetRoadTramType(v->roadtype));
897 TrackdirBits red_signals = TrackStatusToRedSignals(ts); // crossing
899
900 if (IsTileType(tile, TileType::Road)) {
901 if (IsRoadDepot(tile) && (!IsTileOwner(tile, v->owner) || GetRoadDepotDirection(tile) == enterdir)) {
902 /* Road depot owned by another company or with the wrong orientation */
903 trackdirs = TRACKDIR_BIT_NONE;
904 }
905 } else if (IsTileType(tile, TileType::Station) && IsBayRoadStopTile(tile)) {
906 /* Standard road stop (drive-through stops are treated as normal road) */
907
908 if (!IsTileOwner(tile, v->owner) || GetBayRoadStopDir(tile) == enterdir || v->HasArticulatedPart()) {
909 /* different station owner or wrong orientation or the vehicle has articulated parts */
910 trackdirs = TRACKDIR_BIT_NONE;
911 } else {
912 /* Our station */
914
915 if (GetRoadStopType(tile) != rstype) {
916 /* Wrong station type */
917 trackdirs = TRACKDIR_BIT_NONE;
918 } else {
919 /* Proper station type, check if there is free loading bay */
920 if (!_settings_game.pf.roadveh_queue && IsBayRoadStopTile(tile) &&
921 !RoadStop::GetByTile(tile, rstype)->HasFreeBay()) {
922 /* Station is full and RV queuing is off */
923 trackdirs = TRACKDIR_BIT_NONE;
924 }
925 }
926 }
927 }
928 /* The above lookups should be moved to GetTileTrackStatus in the
929 * future, but that requires more changes to the pathfinder and other
930 * stuff, probably even more arguments to GTTS.
931 */
932
933 /* Remove tracks unreachable from the enter dir */
934 trackdirs &= DiagdirReachesTrackdirs(enterdir);
935 if (trackdirs == TRACKDIR_BIT_NONE) {
936 /* If vehicle expected a path, it no longer exists, so invalidate it. */
937 if (!v->path.empty()) v->path.clear();
938 /* No reachable tracks, so we'll reverse */
939 return_track(_road_reverse_table[enterdir]);
940 }
941
942 if (v->reverse_ctr != 0) {
943 bool reverse = true;
944 if (RoadTypeIsTram(v->roadtype)) {
945 /* Trams may only reverse on a tile if it contains at least the straight
946 * trackbits or when it is a valid turning tile (i.e. one roadbit) */
947 RoadBits rb = GetAnyRoadBits(tile, RTT_TRAM);
948 RoadBits straight = AxisToRoadBits(DiagDirToAxis(enterdir));
949 reverse = ((rb & straight) == straight) ||
950 (rb == DiagDirToRoadBits(enterdir));
951 }
952 if (reverse) {
953 v->reverse_ctr = 0;
954 if (v->tile != tile) {
955 return_track(_road_reverse_table[enterdir]);
956 }
957 }
958 }
959
960 if (v->dest_tile == INVALID_TILE) {
961 /* We've got no destination, pick a random track */
962 return_track(PickRandomBit(trackdirs));
963 }
964
965 /* Only one track to choose between? */
966 if (KillFirstBit(trackdirs) == TRACKDIR_BIT_NONE) {
967 if (!v->path.empty() && v->path.back().tile == tile) {
968 /* Vehicle expected a choice here, invalidate its path. */
969 v->path.clear();
970 }
971 return_track(FindFirstBit(trackdirs));
972 }
973
974 /* Attempt to follow cached path. */
975 if (!v->path.empty()) {
976 if (v->path.back().tile != tile) {
977 /* Vehicle didn't expect a choice here, invalidate its path. */
978 v->path.clear();
979 } else {
980 Trackdir trackdir = v->path.back().trackdir;
981
982 if (HasBit(trackdirs, trackdir)) {
983 v->path.pop_back();
984 return_track(trackdir);
985 }
986
987 /* Vehicle expected a choice which is no longer available. */
988 v->path.clear();
989 }
990 }
991
992 best_track = YapfRoadVehicleChooseTrack(v, tile, enterdir, trackdirs, path_found, v->path);
993
994 v->HandlePathfindingResult(path_found);
995
996found_best_track:;
997
998 if (HasBit(red_signals, best_track)) return INVALID_TRACKDIR;
999
1000 return best_track;
1001}
1002
1004 uint8_t x, y;
1005};
1006
1007#include "table/roadveh_movement.h"
1008
1009bool RoadVehLeaveDepot(RoadVehicle *v, bool first)
1010{
1011 /* Don't leave unless v and following wagons are in the depot. */
1012 for (const RoadVehicle *u = v; u != nullptr; u = u->Next()) {
1013 if (u->state != RVSB_IN_DEPOT || u->tile != v->tile) return false;
1014 }
1015
1017 v->direction = DiagDirToDir(dir);
1018
1019 Trackdir tdir = DiagDirToDiagTrackdir(dir);
1020 const RoadDriveEntry *rdp = _road_drive_data[GetRoadTramType(v->roadtype)][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + tdir];
1021
1022 int x = TileX(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].x & 0xF);
1023 int y = TileY(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].y & 0xF);
1024
1025 if (first) {
1026 /* We are leaving a depot, but have to go to the exact same one; re-enter */
1027 if (v->current_order.IsType(OT_GOTO_DEPOT) && v->tile == v->dest_tile) {
1029 return true;
1030 }
1031
1032 if (RoadVehFindCloseTo(v, x, y, v->direction, false) != nullptr) return true;
1033
1036
1037 StartRoadVehSound(v);
1038
1039 /* Vehicle is about to leave a depot */
1040 v->cur_speed = 0;
1041 }
1042
1044 v->state = tdir;
1045 v->frame = RVC_DEPOT_START_FRAME;
1046
1047 v->x_pos = x;
1048 v->y_pos = y;
1049 v->UpdatePosition();
1050 v->UpdateInclination(true, true);
1051
1053
1054 return true;
1055}
1056
1057static Trackdir FollowPreviousRoadVehicle(const RoadVehicle *v, const RoadVehicle *prev, TileIndex tile, DiagDirection entry_dir, bool already_reversed)
1058{
1059 if (prev->tile == v->tile && !already_reversed) {
1060 /* If the previous vehicle is on the same tile as this vehicle is
1061 * then it must have reversed. */
1062 return _road_reverse_table[entry_dir];
1063 }
1064
1065 uint8_t prev_state = prev->state;
1066 Trackdir dir;
1067
1068 if (prev_state == RVSB_WORMHOLE || prev_state == RVSB_IN_DEPOT) {
1069 DiagDirection diag_dir = INVALID_DIAGDIR;
1070
1072 diag_dir = GetTunnelBridgeDirection(tile);
1073 } else if (IsRoadDepotTile(tile)) {
1074 diag_dir = ReverseDiagDir(GetRoadDepotDirection(tile));
1075 }
1076
1077 if (diag_dir == INVALID_DIAGDIR) return INVALID_TRACKDIR;
1078 dir = DiagDirToDiagTrackdir(diag_dir);
1079 } else {
1080 if (already_reversed && (prev->tile != tile || (prev_state < TRACKDIR_END && IsReversingRoadTrackdir(static_cast<Trackdir>(prev_state))))) {
1081 /*
1082 * The vehicle has reversed, but did not go straight back.
1083 * It immediately turn onto another tile. This means that
1084 * the roadstate of the previous vehicle cannot be used
1085 * as the direction we have to go with this vehicle.
1086 *
1087 * Next table is build in the following way:
1088 * - first row for when the vehicle in front went to the northern or
1089 * western tile, second for southern and eastern.
1090 * - columns represent the entry direction.
1091 * - cell values are determined by the Trackdir one has to take from
1092 * the entry dir (column) to the tile in north or south by only
1093 * going over the trackdirs used for turning 90 degrees, i.e.
1094 * TRACKDIR_{UPPER,RIGHT,LOWER,LEFT}_{N,E,S,W}.
1095 */
1096 bool north;
1097 if (prev->tile != tile) {
1098 north = prev->tile < tile;
1099 } else {
1100 north = (prev_state == TRACKDIR_RVREV_NW || prev_state == TRACKDIR_RVREV_NE);
1101 }
1102 static const Trackdir reversed_turn_lookup[2][DIAGDIR_END] = {
1105 dir = reversed_turn_lookup[north ? 0 : 1][ReverseDiagDir(entry_dir)];
1106 } else if (HasBit(prev_state, RVS_IN_DT_ROAD_STOP)) {
1107 dir = (Trackdir)(prev_state & RVSB_ROAD_STOP_TRACKDIR_MASK);
1108 } else if (prev_state < TRACKDIR_END) {
1109 dir = (Trackdir)prev_state;
1110 } else {
1111 return INVALID_TRACKDIR;
1112 }
1113 }
1114
1115 /* Do some sanity checking. */
1116 static const RoadBits required_roadbits[] = {
1119 };
1120 RoadBits required = required_roadbits[dir & 0x07];
1121
1122 if ((required & GetAnyRoadBits(tile, GetRoadTramType(v->roadtype), true)) == ROAD_NONE) {
1123 dir = INVALID_TRACKDIR;
1124 }
1125
1126 return dir;
1127}
1128
1137static bool CanBuildTramTrackOnTile(CompanyID c, TileIndex t, RoadType rt, RoadBits r)
1138{
1139 /* The 'current' company is not necessarily the owner of the vehicle. */
1140 Backup<CompanyID> cur_company(_current_company, c);
1141
1142 CommandCost ret = Command<Commands::BuildRoad>::Do(DoCommandFlag::NoWater, t, r, rt, DRD_NONE, TownID::Invalid());
1143
1144 cur_company.Restore();
1145 return ret.Succeeded();
1146}
1147
1148bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
1149{
1150 if (v->overtaking != 0) {
1152 /* Force us to be not overtaking! */
1153 v->overtaking = 0;
1154 } else if (++v->overtaking_ctr >= RV_OVERTAKE_TIMEOUT) {
1155 /* If overtaking just aborts at a random moment, we can have a out-of-bound problem,
1156 * if the vehicle started a corner. To protect that, only allow an abort of
1157 * overtake if we are on straight roads */
1159 v->overtaking = 0;
1160 }
1161 }
1162 }
1163
1164 /* If this vehicle is in a depot and we've reached this point it must be
1165 * one of the articulated parts. It will stay in the depot until activated
1166 * by the previous vehicle in the chain when it gets to the right place. */
1167 if (v->IsInDepot()) return true;
1168
1169 if (v->state == RVSB_WORMHOLE) {
1170 /* Vehicle is entering a depot or is on a bridge or in a tunnel */
1172
1173 if (v->IsFrontEngine()) {
1174 const Vehicle *u = RoadVehFindCloseTo(v, gp.x, gp.y, v->direction);
1175 if (u != nullptr) {
1176 v->cur_speed = u->First()->cur_speed;
1177 return false;
1178 }
1179 }
1180
1182 /* Vehicle has just entered a bridge or tunnel */
1183 v->x_pos = gp.x;
1184 v->y_pos = gp.y;
1185 v->UpdatePosition();
1186 v->UpdateInclination(true, true);
1187 return true;
1188 }
1189
1190 v->x_pos = gp.x;
1191 v->y_pos = gp.y;
1192 v->UpdatePosition();
1193 if (!v->vehstatus.Test(VehState::Hidden)) v->Vehicle::UpdateViewport(true);
1194 return true;
1195 }
1196
1197 /* Get move position data for next frame.
1198 * For a drive-through road stop use 'straight road' move data.
1199 * In this case v->state is masked to give the road stop entry direction. */
1200 RoadDriveEntry rd = _road_drive_data[GetRoadTramType(v->roadtype)][(
1202 (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking][v->frame + 1];
1203
1204 if (rd.x & RDE_NEXT_TILE) {
1205 TileIndex tile = v->tile + TileOffsByDiagDir((DiagDirection)(rd.x & 3));
1206 Trackdir dir;
1207
1208 if (v->IsFrontEngine()) {
1209 /* If this is the front engine, look for the right path. */
1211 dir = RoadFindPathToDest(v, tile, (DiagDirection)(rd.x & 3));
1212 } else {
1213 dir = _road_reverse_table[(DiagDirection)(rd.x & 3)];
1214 }
1215 } else {
1216 dir = FollowPreviousRoadVehicle(v, prev, tile, (DiagDirection)(rd.x & 3), false);
1217 }
1218
1219 if (dir == INVALID_TRACKDIR) {
1220 if (!v->IsFrontEngine()) FatalError("Disconnecting road vehicle.");
1221 v->cur_speed = 0;
1222 return false;
1223 }
1224
1225again:
1226 uint start_frame = RVC_DEFAULT_START_FRAME;
1227 if (IsReversingRoadTrackdir(dir)) {
1228 /* When turning around we can't be overtaking. */
1229 v->overtaking = 0;
1230
1231 /* Turning around */
1232 if (RoadTypeIsTram(v->roadtype)) {
1233 /* Determine the road bits the tram needs to be able to turn around
1234 * using the 'big' corner loop. */
1235 RoadBits needed;
1236 switch (dir) {
1237 default: NOT_REACHED();
1238 case TRACKDIR_RVREV_NE: needed = ROAD_SW; break;
1239 case TRACKDIR_RVREV_SE: needed = ROAD_NW; break;
1240 case TRACKDIR_RVREV_SW: needed = ROAD_NE; break;
1241 case TRACKDIR_RVREV_NW: needed = ROAD_SE; break;
1242 }
1243 if ((v->Previous() != nullptr && v->Previous()->tile == tile) ||
1244 (v->IsFrontEngine() && IsNormalRoadTile(tile) && !HasRoadWorks(tile) &&
1246 (needed & GetRoadBits(tile, RTT_TRAM)) != ROAD_NONE)) {
1247 /*
1248 * Taking the 'big' corner for trams only happens when:
1249 * - The previous vehicle in this (articulated) tram chain is
1250 * already on the 'next' tile, we just follow them regardless of
1251 * anything. When it is NOT on the 'next' tile, the tram started
1252 * doing a reversing turn when the piece of tram track on the next
1253 * tile did not exist yet. Do not use the big tram loop as that is
1254 * going to cause the tram to split up.
1255 * - Or the front of the tram can drive over the next tile.
1256 */
1257 } else if (!v->IsFrontEngine() || !CanBuildTramTrackOnTile(v->owner, tile, v->roadtype, needed) || ((~needed & GetAnyRoadBits(v->tile, RTT_TRAM, false)) == ROAD_NONE)) {
1258 /*
1259 * Taking the 'small' corner for trams only happens when:
1260 * - We are not the from vehicle of an articulated tram.
1261 * - Or when the company cannot build on the next tile.
1262 *
1263 * The 'small' corner means that the vehicle is on the end of a
1264 * tram track and needs to start turning there. To do this properly
1265 * the tram needs to start at an offset in the tram turning 'code'
1266 * for 'big' corners. It furthermore does not go to the next tile,
1267 * so that needs to be fixed too.
1268 */
1269 tile = v->tile;
1270 start_frame = RVC_TURN_AROUND_START_FRAME_SHORT_TRAM;
1271 } else {
1272 /* The company can build on the next tile, so wait till they do. */
1273 v->cur_speed = 0;
1274 return false;
1275 }
1277 v->cur_speed = 0;
1278 return false;
1279 } else {
1280 tile = v->tile;
1281 }
1282 }
1283
1284 /* Get position data for first frame on the new tile */
1285 const RoadDriveEntry *rdp = _road_drive_data[GetRoadTramType(v->roadtype)][(dir + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking];
1286
1287 int x = TileX(tile) * TILE_SIZE + rdp[start_frame].x;
1288 int y = TileY(tile) * TILE_SIZE + rdp[start_frame].y;
1289
1290 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
1291 if (v->IsFrontEngine()) {
1292 const Vehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
1293 if (u != nullptr) {
1294 v->cur_speed = u->First()->cur_speed;
1295 /* We might be blocked, prevent pathfinding rerun as we already know where we are heading to. */
1296 v->path.emplace_back(dir, tile);
1297 return false;
1298 }
1299 }
1300
1301 auto vets = VehicleEnterTile(v, tile, x, y);
1302 if (vets.Test(VehicleEnterTileState::CannotEnter)) {
1303 if (!IsTileType(tile, TileType::TunnelBridge)) {
1304 v->cur_speed = 0;
1305 return false;
1306 }
1307 /* Try an about turn to re-enter the previous tile */
1308 dir = _road_reverse_table[rd.x & 3];
1309 goto again;
1310 }
1311
1312 if (IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) && IsTileType(v->tile, TileType::Station)) {
1313 if (IsReversingRoadTrackdir(dir) && IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
1314 /* New direction is trying to turn vehicle around.
1315 * We can't turn at the exit of a road stop so wait.*/
1316 v->cur_speed = 0;
1317 return false;
1318 }
1319
1320 /* If we are a drive through road stop and the next tile is of
1321 * the same road stop and the next tile isn't this one (i.e. we
1322 * are not reversing), then keep the reservation and state.
1323 * This way we will not be shortly unregister from the road
1324 * stop. It also makes it possible to load when on the edge of
1325 * two road stops; otherwise you could get vehicles that should
1326 * be loading but are not actually loading. */
1327 if (IsDriveThroughStopTile(v->tile) &&
1329 v->tile != tile) {
1330 /* So, keep 'our' state */
1331 dir = (Trackdir)v->state;
1332 } else if (IsStationRoadStop(v->tile)) {
1333 /* We're not continuing our drive through road stop, so leave. */
1335 }
1336 }
1337
1339 TileIndex old_tile = v->tile;
1340
1341 v->tile = tile;
1342 v->state = (uint8_t)dir;
1343 v->frame = start_frame;
1344 RoadTramType rtt = GetRoadTramType(v->roadtype);
1345 if (GetRoadType(old_tile, rtt) != GetRoadType(tile, rtt)) {
1346 if (v->IsFrontEngine()) {
1348 }
1349 v->First()->CargoChanged();
1350 }
1351 }
1352 if (new_dir != v->direction) {
1353 v->direction = new_dir;
1354 if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2;
1355 }
1356 v->x_pos = x;
1357 v->y_pos = y;
1358 v->UpdatePosition();
1359 RoadZPosAffectSpeed(v, v->UpdateInclination(true, true));
1360 return true;
1361 }
1362
1363 if (rd.x & RDE_TURNED) {
1364 /* Vehicle has finished turning around, it will now head back onto the same tile */
1365 Trackdir dir;
1366 uint turn_around_start_frame = RVC_TURN_AROUND_START_FRAME;
1367
1368 if (RoadTypeIsTram(v->roadtype) && !IsRoadDepotTile(v->tile) && HasExactlyOneBit(GetAnyRoadBits(v->tile, RTT_TRAM, true))) {
1369 /*
1370 * The tram is turning around with one tram 'roadbit'. This means that
1371 * it is using the 'big' corner 'drive data'. However, to support the
1372 * trams to take a small corner, there is a 'turned' marker in the middle
1373 * of the turning 'drive data'. When the tram took the long corner, we
1374 * will still use the 'big' corner drive data, but we advance it one
1375 * frame. We furthermore set the driving direction so the turning is
1376 * going to be properly shown.
1377 */
1378 turn_around_start_frame = RVC_START_FRAME_AFTER_LONG_TRAM;
1379 switch (rd.x & 0x3) {
1380 default: NOT_REACHED();
1381 case DIAGDIR_NW: dir = TRACKDIR_RVREV_SE; break;
1382 case DIAGDIR_NE: dir = TRACKDIR_RVREV_SW; break;
1383 case DIAGDIR_SE: dir = TRACKDIR_RVREV_NW; break;
1384 case DIAGDIR_SW: dir = TRACKDIR_RVREV_NE; break;
1385 }
1386 } else {
1387 if (v->IsFrontEngine()) {
1388 /* If this is the front engine, look for the right path. */
1389 dir = RoadFindPathToDest(v, v->tile, (DiagDirection)(rd.x & 3));
1390 } else {
1391 dir = FollowPreviousRoadVehicle(v, prev, v->tile, (DiagDirection)(rd.x & 3), true);
1392 }
1393 }
1394
1395 if (dir == INVALID_TRACKDIR) {
1396 v->cur_speed = 0;
1397 return false;
1398 }
1399
1400 const RoadDriveEntry *rdp = _road_drive_data[GetRoadTramType(v->roadtype)][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + dir];
1401
1402 int x = TileX(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].x;
1403 int y = TileY(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].y;
1404
1405 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
1406 if (v->IsFrontEngine()) {
1407 const Vehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
1408 if (u != nullptr) {
1409 v->cur_speed = u->First()->cur_speed;
1410 /* We might be blocked, prevent pathfinding rerun as we already know where we are heading to. */
1411 v->path.emplace_back(dir, v->tile);
1412 return false;
1413 }
1414 }
1415
1416 auto vets = VehicleEnterTile(v, v->tile, x, y);
1417 if (vets.Test(VehicleEnterTileState::CannotEnter)) {
1418 v->cur_speed = 0;
1419 return false;
1420 }
1421
1422 v->state = dir;
1423 v->frame = turn_around_start_frame;
1424
1425 if (new_dir != v->direction) {
1426 v->direction = new_dir;
1427 if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2;
1428 }
1429
1430 v->x_pos = x;
1431 v->y_pos = y;
1432 v->UpdatePosition();
1433 RoadZPosAffectSpeed(v, v->UpdateInclination(true, true));
1434 return true;
1435 }
1436
1437 /* This vehicle is not in a wormhole and it hasn't entered a new tile. If
1438 * it's on a depot tile, check if it's time to activate the next vehicle in
1439 * the chain yet. */
1440 if (v->Next() != nullptr && IsRoadDepotTile(v->tile)) {
1441 if (v->frame == v->gcache.cached_veh_length + RVC_DEPOT_START_FRAME) {
1442 RoadVehLeaveDepot(v->Next(), false);
1443 }
1444 }
1445
1446 /* Calculate new position for the vehicle */
1447 int x = (v->x_pos & ~15) + (rd.x & 15);
1448 int y = (v->y_pos & ~15) + (rd.y & 15);
1449
1450 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
1451
1452 if (v->IsFrontEngine() && !IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
1453 /* Vehicle is not in a road stop.
1454 * Check for another vehicle to overtake */
1455 RoadVehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
1456
1457 if (u != nullptr) {
1458 u = u->First();
1459 /* There is a vehicle in front overtake it if possible */
1460 if (v->overtaking == 0) RoadVehCheckOvertake(v, u);
1461 if (v->overtaking == 0) v->cur_speed = u->cur_speed;
1462
1463 /* In case an RV is stopped in a road stop, why not try to load? */
1464 if (v->cur_speed == 0 && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
1466 v->owner == GetTileOwner(v->tile) && !v->current_order.IsType(OT_LEAVESTATION) &&
1469 v->last_station_visited = st->index;
1470 RoadVehArrivesAt(v, st);
1471 v->BeginLoading();
1473 TriggerRoadStopAnimation(st, v->tile, StationAnimationTrigger::VehicleArrives);
1474 }
1475 return false;
1476 }
1477 }
1478
1479 Direction old_dir = v->direction;
1480 if (new_dir != old_dir) {
1481 v->direction = new_dir;
1482 if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2;
1483
1484 /* Delay the vehicle in curves by making it require one additional frame per turning direction (two in total).
1485 * A vehicle has to spend at least 9 frames on a tile, so the following articulated part can follow.
1486 * (The following part may only be one tile behind, and the front part is moved before the following ones.)
1487 * The short (inner) curve has 8 frames, this elongates it to 10. */
1488 v->UpdateViewport(true, true);
1489 return true;
1490 }
1491
1492 /* If the vehicle is in a normal road stop and the frame equals the stop frame OR
1493 * if the vehicle is in a drive-through road stop and this is the destination station
1494 * and it's the correct type of stop (bus or truck) and the frame equals the stop frame...
1495 * (the station test and stop type test ensure that other vehicles, using the road stop as
1496 * a through route, do not stop) */
1497 if (v->IsFrontEngine() && ((IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END) &&
1498 _road_stop_stop_frame[v->state - RVSB_IN_ROAD_STOP + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)] == v->frame) ||
1499 (IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
1501 v->owner == GetTileOwner(v->tile) &&
1503 v->frame == RVC_DRIVE_THROUGH_STOP_FRAME))) {
1504
1507
1508 /* Vehicle is at the stop position (at a bay) in a road stop.
1509 * Note, if vehicle is loading/unloading it has already been handled,
1510 * so if we get here the vehicle has just arrived or is just ready to leave. */
1511 if (!HasBit(v->state, RVS_ENTERED_STOP)) {
1512 /* Vehicle has arrived at a bay in a road stop */
1513
1514 if (IsDriveThroughStopTile(v->tile)) {
1515 TileIndex next_tile = TileAddByDir(v->tile, v->direction);
1516
1517 /* Check if next inline bay is free and has compatible road. */
1519 v->frame++;
1520 v->x_pos = x;
1521 v->y_pos = y;
1522 v->UpdatePosition();
1523 RoadZPosAffectSpeed(v, v->UpdateInclination(true, false));
1524 return true;
1525 }
1526 }
1527
1528 rs->SetEntranceBusy(false);
1530
1531 v->last_station_visited = st->index;
1532
1533 if (IsDriveThroughStopTile(v->tile) || (v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetDestination() == st->index)) {
1534 RoadVehArrivesAt(v, st);
1535 v->BeginLoading();
1537 TriggerRoadStopAnimation(st, v->tile, StationAnimationTrigger::VehicleArrives);
1538 return false;
1539 }
1540 } else {
1541 /* Vehicle is ready to leave a bay in a road stop */
1542 if (rs->IsEntranceBusy()) {
1543 /* Road stop entrance is busy, so wait as there is nowhere else to go */
1544 v->cur_speed = 0;
1545 return false;
1546 }
1547 if (v->current_order.IsType(OT_LEAVESTATION)) v->current_order.Free();
1548 }
1549
1550 if (IsBayRoadStopTile(v->tile)) rs->SetEntranceBusy(true);
1551
1552 StartRoadVehSound(v);
1554 }
1555
1556 /* Check tile position conditions - i.e. stop position in depot,
1557 * entry onto bridge or into tunnel */
1558 auto vets = VehicleEnterTile(v, v->tile, x, y);
1559 if (vets.Test(VehicleEnterTileState::CannotEnter)) {
1560 v->cur_speed = 0;
1561 return false;
1562 }
1563
1564 if (v->current_order.IsType(OT_LEAVESTATION) && IsDriveThroughStopTile(v->tile)) {
1565 v->current_order.Free();
1566 }
1567
1568 /* Move to next frame unless vehicle arrived at a stop position
1569 * in a depot or entered a tunnel/bridge */
1570 if (!vets.Test(VehicleEnterTileState::EnteredWormhole)) v->frame++;
1571 v->x_pos = x;
1572 v->y_pos = y;
1573 v->UpdatePosition();
1574 RoadZPosAffectSpeed(v, v->UpdateInclination(false, true));
1575 return true;
1576}
1577
1578static bool RoadVehController(RoadVehicle *v)
1579{
1580 /* decrease counters */
1581 v->current_order_time++;
1582 if (v->reverse_ctr != 0) v->reverse_ctr--;
1583
1584 /* handle crashed */
1585 if (v->vehstatus.Test(VehState::Crashed) || RoadVehCheckTrainCrash(v)) {
1586 return RoadVehIsCrashed(v);
1587 }
1588
1589 /* road vehicle has broken down? */
1590 if (v->HandleBreakdown()) return true;
1592 v->SetLastSpeed();
1593 return true;
1594 }
1595
1596 ProcessOrders(v);
1597 v->HandleLoading();
1598
1599 if (v->current_order.IsType(OT_LOADING)) return true;
1600
1601 if (v->IsInDepot()) {
1602 /* Check if we should wait here for unbunching. */
1603 if (v->IsWaitingForUnbunching()) return true;
1604 if (RoadVehLeaveDepot(v, true)) return true;
1605 }
1606
1607 v->ShowVisualEffect();
1608
1609 /* Check how far the vehicle needs to proceed */
1610 int j = v->UpdateSpeed();
1611
1612 int adv_spd = v->GetAdvanceDistance();
1613 bool blocked = false;
1614 while (j >= adv_spd) {
1615 j -= adv_spd;
1616
1617 RoadVehicle *u = v;
1618 for (RoadVehicle *prev = nullptr; u != nullptr; prev = u, u = u->Next()) {
1619 if (!IndividualRoadVehicleController(u, prev)) {
1620 blocked = true;
1621 break;
1622 }
1623 }
1624 if (blocked) break;
1625
1626 /* Determine distance to next map position */
1627 adv_spd = v->GetAdvanceDistance();
1628
1629 /* Test for a collision, but only if another movement will occur. */
1630 if (j >= adv_spd && RoadVehCheckTrainCrash(v)) break;
1631 }
1632
1633 v->SetLastSpeed();
1634
1635 for (RoadVehicle *u = v; u != nullptr; u = u->Next()) {
1636 if (u->vehstatus.Test(VehState::Hidden)) continue;
1637
1638 u->UpdateViewport(false, false);
1639 }
1640
1641 /* If movement is blocked, set 'progress' to its maximum, so the roadvehicle does
1642 * not accelerate again before it can actually move. I.e. make sure it tries to advance again
1643 * on next tick to discover whether it is still blocked. */
1644 if (v->progress == 0) v->progress = blocked ? adv_spd - 1 : j;
1645
1646 return true;
1647}
1648
1650{
1651 const Engine *e = this->GetEngine();
1652 if (e->VehInfo<RoadVehicleInfo>().running_cost_class == Price::Invalid) return 0;
1653
1654 uint cost_factor = GetVehicleProperty(this, PROP_ROADVEH_RUNNING_COST_FACTOR, e->VehInfo<RoadVehicleInfo>().running_cost);
1655 if (cost_factor == 0) return 0;
1656
1657 return GetPrice(e->VehInfo<RoadVehicleInfo>().running_cost_class, cost_factor, e->GetGRF());
1658}
1659
1661{
1663
1664 this->tick_counter++;
1665
1666 if (this->IsFrontEngine()) {
1667 if (!this->vehstatus.Test(VehState::Stopped)) this->running_ticks++;
1668 return RoadVehController(this);
1669 }
1670
1671 return true;
1672}
1673
1674void RoadVehicle::SetDestTile(TileIndex tile)
1675{
1676 if (tile == this->dest_tile) return;
1677 this->path.clear();
1678 this->dest_tile = tile;
1679}
1680
1681static void CheckIfRoadVehNeedsService(RoadVehicle *v)
1682{
1683 /* If we already got a slot at a stop, use that FIRST, and go to a depot later */
1684 if (Company::Get(v->owner)->settings.vehicle.servint_roadveh == 0 || !v->NeedsAutomaticServicing()) return;
1685 if (v->IsChainInDepot()) {
1687 return;
1688 }
1689
1690 uint max_penalty = _settings_game.pf.yapf.maximum_go_to_depot_penalty;
1691
1692 FindDepotData rfdd = FindClosestRoadDepot(v, max_penalty);
1693 /* Only go to the depot if it is not too far out of our way. */
1694 if (rfdd.best_length == UINT_MAX || rfdd.best_length > max_penalty) {
1695 if (v->current_order.IsType(OT_GOTO_DEPOT)) {
1696 /* If we were already heading for a depot but it has
1697 * suddenly moved farther away, we continue our normal
1698 * schedule? */
1701 }
1702 return;
1703 }
1704
1705 DepotID depot = GetDepotIndex(rfdd.tile);
1706
1707 if (v->current_order.IsType(OT_GOTO_DEPOT) &&
1709 !Chance16(1, 20)) {
1710 return;
1711 }
1712
1715 v->SetDestTile(rfdd.tile);
1717}
1718
1721{
1722 if (!this->IsFrontEngine()) return;
1723 AgeVehicle(this);
1724}
1725
1728{
1729 if (!this->IsFrontEngine()) return;
1730 EconomyAgeVehicle(this);
1731
1732 if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
1733 if (this->blocked_ctr == 0) CheckVehicleBreakdown(this);
1734
1735 CheckIfRoadVehNeedsService(this);
1736
1737 CheckOrders(this);
1738
1739 if (this->running_ticks == 0) return;
1740
1742
1743 this->profit_this_year -= cost.GetCost();
1744 this->running_ticks = 0;
1745
1747
1750}
1751
1753{
1754 if (this->vehstatus.Test(VehState::Crashed)) return INVALID_TRACKDIR;
1755
1756 if (this->IsInDepot()) {
1757 /* We'll assume the road vehicle is facing outwards */
1758 return DiagDirToDiagTrackdir(GetRoadDepotDirection(this->tile));
1759 }
1760
1761 if (IsBayRoadStopTile(this->tile)) {
1762 /* We'll assume the road vehicle is facing outwards */
1763 return DiagDirToDiagTrackdir(GetBayRoadStopDir(this->tile)); // Road vehicle in a station
1764 }
1765
1766 /* Drive through road stops / wormholes (tunnels) */
1768
1769 /* If vehicle's state is a valid track direction (vehicle is not turning around) return it,
1770 * otherwise transform it into a valid track direction */
1771 return (Trackdir)((IsReversingRoadTrackdir((Trackdir)this->state)) ? (this->state - 6) : this->state);
1772}
1773
1775{
1776 uint16_t weight = CargoSpec::Get(this->cargo_type)->WeightOfNUnits(this->GetEngine()->DetermineCapacity(this));
1777
1778 /* Vehicle weight is not added for articulated parts. */
1779 if (!this->IsArticulatedPart()) {
1780 /* Road vehicle weight is in units of 1/4 t. */
1781 weight += GetVehicleProperty(this, PROP_ROADVEH_WEIGHT, RoadVehInfo(this->engine_type)->weight) / 4;
1782 }
1783
1784 return weight;
1785}
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.
Class for backupping variables and making sure they are restored later.
@ BuiltAsPrototype
Vehicle is a prototype (accepted as exclusive preview).
constexpr bool HasExactlyOneBit(T value)
Test whether value has exactly 1 bit set.
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 uint CountBits(T value)
Counts the number of set bits in a variable.
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T KillFirstBit(T value)
Clear the first bit in an integer.
const BridgeSpec * GetBridgeSpec(BridgeType i)
Get the specification of a bridge type.
Definition bridge.h:60
BridgeType GetBridgeType(Tile t)
Determines the type of bridge on a tile.
Definition bridge_map.h:56
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:104
@ Passengers
Passengers.
Definition cargotype.h:50
bool IsCargoInClass(CargoType cargo, CargoClasses cc)
Does cargo c have cargo class cc?
Definition cargotype.h:236
static void NewEvent(CompanyID company, ScriptEvent *event)
Queue a new event for an AI.
Definition ai_core.cpp:235
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Reset()
Reset all bits.
constexpr bool Any(const Timpl &other) const
Test if any of the given values are set.
Common return value for all commands.
bool Succeeded() const
Did this command succeed?
Money GetCost() const
The costs as made up to this moment.
bool Failed() const
Did this command fail?
Container for an encoded string, created by GetEncodedString.
uint32_t GetGRFID() const
Retrieve the GRF ID of the NewGRF the engine is tied to.
Definition engine.cpp:160
uint16_t reliability_spd_dec
Speed of reliability decay between services (per day).
Definition engine_base.h:50
const GRFFile * GetGRF() const
Retrieve the NewGRF the engine is tied to.
EngineFlags flags
Flags of the engine.
Definition engine_base.h:57
uint8_t original_image_index
Original vehicle image index, thus the image index of the overridden vehicle.
Definition engine_base.h:61
TimerGameCalendar::Date GetLifeLengthInDays() const
Returns the vehicle's (not model's!) life length in days.
Definition engine.cpp:446
CargoType GetDefaultCargoType() const
Determines the default cargo type of an engine.
Definition engine_base.h:94
uint16_t reliability
Current reliability of the engine.
Definition engine_base.h:49
static void NewEvent(class ScriptEvent *event)
Queue a new event for a Game Script.
RAII class for measuring multi-step elements of performance.
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 Date date
Current date in days (day counter).
Iterate over all vehicles near a given world coordinate.
Iterate over all vehicles on a tile.
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ NoWater
don't allow building on water
@ Execute
execute the given command
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.
CompanyID _current_company
Company currently doing an action.
void SubtractMoneyFromCompanyFract(CompanyID company, const CommandCost &cst)
Subtract money from a company, including the money fraction.
Functions related to companies.
Map related accessors for depots.
DepotID GetDepotIndex(Tile t)
Get the index of which depot is attached to the tile.
Definition depot_map.h:53
PoolID< uint16_t, struct DepotIDTag, 64000, 0xFFFF > DepotID
Type for the unique identifier of depots.
Definition depot_type.h:15
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.
Direction ChangeDir(Direction d, DirDiff delta)
Change a direction by a given difference.
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.
DirDiff
Enumeration for the difference between two directions.
@ DIRDIFF_45LEFT
Angle of 45 degrees left.
@ DIRDIFF_REVERSE
One direction is the opposite of the other one.
@ DIRDIFF_45RIGHT
Angle of 45 degrees right.
@ DIRDIFF_SAME
Both directions faces to the same direction.
Direction
Defines the 8 directions on the map.
@ DIR_SW
Southwest.
@ DIR_NW
Northwest.
@ INVALID_DIR
Flag for an invalid direction.
@ DIR_N
North.
@ DIR_SE
Southeast.
@ DIR_S
South.
@ DIR_NE
Northeast.
@ DIR_W
West.
@ DIR_E
East.
DiagDirection
Enumeration for diagonal directions.
@ DIAGDIR_NE
Northeast, upper right on your monitor.
@ DIAGDIR_NW
Northwest.
@ DIAGDIR_SE
Southeast.
@ DIAGDIR_END
Used for iterations.
@ INVALID_DIAGDIR
Flag for an invalid DiagDirection.
@ DIAGDIR_SW
Southwest.
Money GetPrice(Price index, uint cost_factor, const GRFFile *grf_file, int shift)
Determine a certain price.
Definition economy.cpp:940
@ EXPENSES_ROADVEH_RUN
Running costs road vehicles.
@ Invalid
Invalid base price.
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_LARGE
Various explosions.
PoolID< uint16_t, struct EngineIDTag, 64000, 0xFFFF > EngineID
Unique identification number of an engine.
Definition engine_type.h:26
@ ExclusivePreview
This vehicle is in the exclusive preview stage, either being used or being offered to a company.
Error reporting related functions.
fluid_settings_t * settings
FluidSynth settings handle.
Types for recording game performance data.
@ PFE_GL_ROADVEHS
Time spend processing road vehicles.
Base functions for all Games.
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
@ AS_BRAKE
We want to stop.
@ GVF_SUPPRESS_IMPLICIT_ORDERS
Disable insertion and removal of automatic orders until the vehicle completes the real order.
TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
Returns information about trackdirs and signal states.
int GetSlopePixelZ(int x, int y, bool ground_vehicle)
Return world Z coordinate of a given point of a tile.
#define Rect
Macro that prevents name conflicts between included headers.
#define Point
Macro that prevents name conflicts between included headers.
TileIndex TileAddByDir(TileIndex tile, Direction dir)
Adds a Direction to a tile.
Definition map_func.h:601
static uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:427
static uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:417
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition map_func.h:572
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition math_func.hpp:23
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
Base for the NewGRF implementation.
@ CBID_VEHICLE_LENGTH
Vehicle length, returns the amount of 1/8's the vehicle is shorter for trains and RVs.
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.
uint16_t GetVehicleCallback(CallbackID callback, uint32_t param1, uint32_t param2, EngineID engine, const Vehicle *v, std::span< int32_t > regs100)
Evaluate a newgrf callback for vehicles.
@ PROP_ROADVEH_CARGO_AGE_PERIOD
Number of ticks before carried cargo is aged.
@ PROP_ROADVEH_WEIGHT
Weight in 1/4 t.
@ PROP_ROADVEH_RUNNING_COST_FACTOR
Yearly runningcost.
@ PROP_ROADVEH_SHORTEN_FACTOR
Shorter vehicles.
@ PROP_ROADVEH_SPEED
Max. speed: 1 unit = 1/0.8 mph = 2 km-ish/h.
void TriggerRoadStopRandomisation(BaseStation *st, TileIndex tile, StationRandomTrigger trigger, CargoType cargo_type)
Trigger road stop randomisation.
NewGRF definitions and structures for road stops.
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.
Functions related to news.
void AddVehicleNewsItem(EncodedString &&headline, NewsType type, VehicleID vehicle, StationID station=StationID::Invalid())
Adds a newsitem referencing a vehicle.
Definition news_func.h:30
NewsType
Type of news.
Definition news_type.h:29
@ ArrivalCompany
First vehicle arrived for company.
Definition news_type.h:30
@ AccidentOther
An accident or disaster has occurred.
Definition news_type.h:33
@ ArrivalOther
First vehicle arrived for competitor.
Definition news_type.h:31
@ Accident
An accident or disaster has occurred.
Definition news_type.h:32
bool ProcessOrders(Vehicle *v)
Handle the orders of a vehicle and determine the next place to go to if needed.
void CheckOrders(const Vehicle *v)
Check the orders of a vehicle, to see if there are invalid orders and stuff.
@ NoIntermediate
The vehicle will not stop at any stations it passes except the destination, aka non-stop.
Definition order_type.h:88
@ Service
This depot order is because of the servicing limit.
Definition order_type.h:108
Pseudo random number generator.
uint32_t RandomRange(uint32_t limit, const std::source_location location=std::source_location::current())
Pick a random number between 0 and limit - 1, inclusive.
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.
const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition road.h:215
Road related functions.
RoadBits AxisToRoadBits(Axis a)
Create the road-part which belongs to the given Axis.
Definition road_func.h:111
RoadBits DiagDirToRoadBits(DiagDirection d)
Create the road-part which belongs to the given DiagDirection.
Definition road_func.h:96
RoadBits GetAnyRoadBits(Tile tile, RoadTramType rtt, bool straight_tunnel_bridge_entrance)
Returns the RoadBits on an arbitrary tile Special behaviour:
Definition road_map.cpp:54
bool IsLevelCrossingTile(Tile t)
Return whether a tile is a level crossing tile.
Definition road_map.h:79
RoadBits GetRoadBits(Tile t, RoadTramType rtt)
Get the present road bits for a specific road type.
Definition road_map.h:112
static bool IsRoadDepotTile(Tile t)
Return whether a tile is a road depot tile.
Definition road_map.h:100
bool HasTileAnyRoadType(Tile t, RoadTypes rts)
Check if a tile has one of the specified road types.
Definition road_map.h:206
DisallowedRoadDirections GetDisallowedRoadDirections(Tile t)
Gets the disallowed directions.
Definition road_map.h:285
DiagDirection GetRoadDepotDirection(Tile t)
Get the direction of the exit of a road depot.
Definition road_map.h:550
static bool IsRoadDepot(Tile t)
Return whether a tile is a road depot.
Definition road_map.h:90
static bool IsNormalRoadTile(Tile t)
Return whether a tile is a normal road tile.
Definition road_map.h:58
bool HasRoadWorks(Tile t)
Check if a tile has road works.
Definition road_map.h:493
RoadBits
Enumeration for the road parts on a tile.
Definition road_type.h:56
@ ROAD_SW
South-west part.
Definition road_type.h:59
@ ROAD_NONE
No road-part is build.
Definition road_type.h:57
@ ROAD_NE
North-east part.
Definition road_type.h:61
@ ROAD_SE
South-east part.
Definition road_type.h:60
@ ROAD_Y
Full road along the y-axis (north-west + south-east).
Definition road_type.h:63
@ ROAD_NW
North-west part.
Definition road_type.h:58
@ ROAD_X
Full road along the x-axis (south-west + north-east).
Definition road_type.h:62
RoadTramType
The different types of road type.
Definition road_type.h:37
@ RTT_TRAM
Tram road type.
Definition road_type.h:39
RoadType
The different roadtypes we support.
Definition road_type.h:23
@ DRD_NONE
None of the directions are disallowed.
Definition road_type.h:78
Base class for roadstops.
Road vehicle states.
@ RVSB_IN_DT_ROAD_STOP
The vehicle is in a drive-through road stop.
Definition roadveh.h:51
@ RVS_ENTERED_STOP
Only set when a vehicle has entered the stop.
Definition roadveh.h:43
@ RVSB_IN_ROAD_STOP
The vehicle is in a road stop.
Definition roadveh.h:49
@ RVSB_ROAD_STOP_TRACKDIR_MASK
Only bits 0 and 3 are used to encode the trackdir for road stops.
Definition roadveh.h:57
@ RVS_IN_DT_ROAD_STOP
The vehicle is in a drive-through road stop.
Definition roadveh.h:46
@ RVSB_TRACKDIR_MASK
The mask used to extract track dirs.
Definition roadveh.h:56
@ RVSB_DRIVE_SIDE
The vehicle is at the opposite side of the road.
Definition roadveh.h:54
@ RVSB_IN_DEPOT
The vehicle is in a depot.
Definition roadveh.h:38
@ RVSB_WORMHOLE
The vehicle is in a tunnel and/or bridge.
Definition roadveh.h:39
@ RVS_DRIVE_SIDE
Only used when retrieving move data.
Definition roadveh.h:44
static const uint RDE_TURNED
We just finished turning.
Definition roadveh.h:62
static const uint8_t RV_OVERTAKE_TIMEOUT
The number of ticks a vehicle has for overtaking.
Definition roadveh.h:79
static const uint RDE_NEXT_TILE
State information about the Road Vehicle controller.
Definition roadveh.h:61
static bool RoadVehIsCrashed(RoadVehicle *v)
Road vehicle chain has crashed.
static uint GetRoadVehLength(const RoadVehicle *v)
Get length of a road vehicle.
static void RoadVehArrivesAt(const RoadVehicle *v, Station *st)
A road vehicle arrives at a station.
static bool CheckRoadBlockedForOvertaking(OvertakeData *od)
Check if overtaking is possible on a piece of track.
void RoadVehUpdateCache(RoadVehicle *v, bool same_length)
Update the cache of a road vehicle.
static bool CanBuildTramTrackOnTile(CompanyID c, TileIndex t, RoadType rt, RoadBits r)
Can a tram track build without destruction on the given tile?
void GetRoadVehSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type)
Get the size of the sprite of a road vehicle sprite heading west (used for lists).
CommandCost CmdBuildRoadVehicle(DoCommandFlags flags, TileIndex tile, const Engine *e, Vehicle **ret)
Build a road vehicle.
CommandCost CmdTurnRoadVeh(DoCommandFlags flags, VehicleID veh_id)
Turn a roadvehicle around.
void DrawRoadVehEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type)
Draw a road vehicle engine.
static Trackdir RoadFindPathToDest(RoadVehicle *v, TileIndex tile, DiagDirection enterdir)
Returns direction to for a road vehicle to take or INVALID_TRACKDIR if the direction is currently blo...
static void DeleteLastRoadVeh(RoadVehicle *v)
Delete last vehicle of a chain road vehicles.
Command definitions related to road vehicles.
Data about how a road vehicle must drive on a tile.
const uint8_t _road_stop_stop_frame[]
Table of road stop stop frames, when to stop at a road stop.
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:61
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
Functions related to sound.
@ SND_19_DEPARTURE_OLD_RV_1
23 == 0x17 Station departure: truck and old bus (1) (non-toyland)
Definition sound_type.h:71
@ SND_12_EXPLOSION
16 == 0x10 Destruction, crashes, disasters, ...
Definition sound_type.h:64
@ SND_1A_DEPARTURE_OLD_RV_2
24 == 0x18 Station departure: truck and old bus (2) (random variation of SND_19_DEPARTURE_OLD_RV_1) (...
Definition sound_type.h:72
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition sprites.h:1619
Base classes/functions for stations.
void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint radius)
Forcibly modify station ratings near a given tile.
bool IsBayRoadStopTile(Tile t)
Is tile t a bay (non-drive through) road stop station?
bool IsDriveThroughStopTile(Tile t)
Is tile t a drive through road stop station or waypoint?
StationID GetStationIndex(Tile t)
Get StationID from a tile.
Definition station_map.h:28
bool IsStationRoadStop(Tile t)
Is the station at t a road station?
DiagDirection GetBayRoadStopDir(Tile t)
Gets the direction the bay road stop entrance points towards.
RoadStopType GetRoadStopType(Tile t)
Get the road stop type of this tile.
Definition station_map.h:56
RoadStopType
Types of RoadStops.
@ Bus
A standard stop for buses.
@ Truck
A standard stop for trucks.
@ HVOT_TRUCK
Station has seen a truck.
@ HVOT_BUS
Station has seen a bus.
@ VehicleArrives
Trigger platform when train arrives.
@ VehicleArrives
Trigger platform when train arrives.
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:271
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:90
Functions related to OTTD's strings.
Class to backup a specific variable and restore it later.
void Restore()
Restore the variable.
TimerGameTick::Ticks current_order_time
How many ticks have passed since this order started.
void ResetDepotUnbunching()
Resets all the data used for depot unbunching.
TileIndex xy
Base tile of the station.
static BaseStation * GetByTile(TileIndex tile)
Get the base station belonging to a specific tile.
VehicleType type
Type of vehicle.
uint16_t speed
maximum travel speed (1 unit = 1/1.6 mph = 1 km-ish/h)
Definition bridge.h:39
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:137
Structure to return information about the closest depot location, and whether it could be found.
T y
Y coordinate.
T x
X coordinate.
Helper container to find a depot.
uint best_length
The distance towards the depot in penalty, or UINT_MAX if not found.
TileIndex tile
The tile of the depot.
Position information of a vehicle after it moved.
TileIndex new_tile
Tile of the vehicle after moving.
int y
x and y position of the vehicle after moving
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...
bool IsChainInDepot() const override
Check whether the whole vehicle chain is in the depot.
int UpdateInclination(bool new_tile, bool update_delta)
Checks if the vehicle is in a slope and sets the required flags in that case.
uint Crash(bool flooded) override
Common code executed for crashed ground vehicles.
uint DoUpdateSpeed(uint accel, int min_speed, int max_speed)
void SetLastSpeed()
Update the GUI variant of the current speed of the vehicle.
DestinationID GetDestination() const
Gets the destination of this order.
Definition order_base.h:99
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition order_base.h:66
void MakeDummy()
Makes this order a Dummy order.
void MakeGoToDepot(DestinationID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type=OrderNonStopFlag::NoIntermediate, OrderDepotActionFlags action={}, CargoType cargo=CARGO_NO_REFIT)
Makes this order a Go To Depot order.
Definition order_cmd.cpp:73
void Free()
'Free' the order
Definition order_cmd.cpp:47
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...
OrderNonStopFlags GetNonStopType() const
At which stations must we stop?
Definition order_base.h:146
static Engine * Get(auto index)
static T * Create(Targs &&... args)
static Vehicle * GetIfValid(auto index)
int Width() const
Get width of Rect.
int Height() const
Get height of Rect.
A Stop for a Road Vehicle.
void SetEntranceBusy(bool busy)
Makes an entrance occupied or free.
void Leave(RoadVehicle *rv)
Leave the road stop.
Definition roadstop.cpp:203
bool IsEntranceBusy() const
Checks whether the entrance of the road stop is occupied by a vehicle.
static bool IsDriveThroughRoadStopContinuation(TileIndex rs, TileIndex next)
Checks whether the 'next' tile is still part of the road same drive through stop 'rs' in the same dir...
Definition roadstop.cpp:292
static RoadStop * GetByTile(TileIndex tile, RoadStopType type)
Find a roadstop at given tile.
Definition roadstop.cpp:253
Information about a road vehicle.
Buses, trucks and trams belong to this class.
Definition roadveh.h:98
uint Crash(bool flooded=false) override
Common code executed for crashed ground vehicles.
TileIndex GetOrderStationLocation(StationID station) override
Determine the location for the station where the vehicle goes to next.
void OnNewEconomyDay() override
Economy day handler.
uint8_t state
Definition roadveh.h:100
int GetDisplayImageWidth(Point *offset=nullptr) const
Get the width of a road vehicle image in the GUI.
Money GetRunningCost() const override
Gets the running cost of a vehicle.
bool IsPrimaryVehicle() const override
Whether this is the primary vehicle in the chain.
Definition roadveh.h:121
uint16_t GetMaxWeight() const override
Calculates the weight value that this vehicle will have when fully loaded with its current cargo.
RoadTypes compatible_roadtypes
NOSAVE: Roadtypes this consist is powered on.
Definition roadveh.h:110
AccelStatus GetAccelerationStatus() const
Checks the current acceleration status of this vehicle.
Definition roadveh.h:222
void UpdateDeltaXY() override
Updates the x and y offsets and the size of the sprite used for this vehicle.
uint16_t crashed_ctr
Animation counter when the vehicle has crashed.
Definition roadveh.h:105
bool IsBus() const
Check whether a roadvehicle is a bus.
uint8_t overtaking_ctr
The length of the current overtake attempt.
Definition roadveh.h:104
void OnNewCalendarDay() override
Calander day handler.
bool IsInDepot() const override
Check whether the vehicle is in the depot.
Definition roadveh.h:127
void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const override
Gets the sprite to show for the given direction.
RoadVehPathCache path
Cached path.
Definition roadveh.h:99
Trackdir GetVehicleTrackdir() const override
Returns the Trackdir on which the vehicle is currently located.
int GetCurrentMaxSpeed() const override
Calculates the maximum speed of the vehicle under its current conditions.
RoadType roadtype
NOSAVE: Roadtype of this vehicle.
Definition roadveh.h:108
uint8_t overtaking
Set to RVSB_DRIVE_SIDE when overtaking, otherwise 0.
Definition roadveh.h:103
int UpdateSpeed()
This function looks at the vehicle and updates its speed (cur_speed and subspeed) variables.
bool Tick() override
Calls the tick handler of the vehicle.
ClosestDepot FindClosestDepot() override
Find the closest depot for this vehicle and tell us the location, DestinationID and whether we should...
void MarkDirty() override
Marks the vehicles to be redrawn and updates cached variables.
static Station * Get(auto index)
T * Next() const
Get next vehicle in the chain.
T * Previous() const
Get previous vehicle in the chain.
static RoadVehicle * From(Vehicle *v)
T * First() const
Get the first vehicle in the chain.
void UpdateViewport(bool force_update, bool update_delta)
Update vehicle sprite- and position caches.
Station data structure.
uint16_t cached_max_speed
Maximum speed of the consist (minimum of the max speed of all vehicles in the consist).
Sprite sequence for a vehicle part.
bool IsValid() const
Check whether the sequence contains any sprites.
void GetBounds(Rect *bounds) const
Determine shared bounds of all sprites.
Definition vehicle.cpp:114
void Set(SpriteID sprite)
Assign a single sprite to the sequence.
void Draw(int x, int y, PaletteID default_pal, bool force_pal) const
Draw the sprite sequence.
Definition vehicle.cpp:142
Vehicle data structure.
EngineID engine_type
The type of engine used for this vehicle.
int32_t z_pos
z coordinate.
Direction direction
facing
const Engine * GetEngine() const
Retrieves the engine of the vehicle.
Definition vehicle.cpp:719
void IncrementRealOrderIndex()
Advanced cur_real_order_index to the next real order, keeps care of the wrap-around and invalidates t...
VehicleCargoList cargo
The cargo this vehicle is carrying.
uint8_t day_counter
Increased by one for each day.
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:2421
Money profit_this_year
Profit this year << 8, low 8 bits are fract.
bool HasArticulatedPart() const
Check if an engine has an articulated part.
SpriteID colourmap
NOSAVE: cached colour mapping.
uint8_t breakdown_ctr
Counter for managing breakdown events.
uint GetAdvanceDistance()
Determines the vehicle "progress" needed for moving a step.
VehStates vehstatus
Status.
bool IsArticulatedPart() const
Check if the vehicle is an articulated part of an engine.
void LeaveUnbunchingDepot()
Leave an unbunching depot and calculate the next departure time for shared order vehicles.
Definition vehicle.cpp:2500
CargoType cargo_type
type of cargo this vehicle is carrying
Vehicle * First() const
Get the first vehicle of this vehicle chain.
Order current_order
The current order (+ status, like: loading).
void HandlePathfindingResult(bool path_found)
Handle the pathfinding result, especially the lost status.
Definition vehicle.cpp:763
int32_t y_pos
y coordinate.
int32_t x_pos
x coordinate.
VehicleCache vcache
Cache of often used vehicle values.
SpriteBounds bounds
Bounding box of vehicle.
void BeginLoading()
Prepare everything to begin the loading when arriving at a station.
Definition vehicle.cpp:2196
uint8_t spritenum
currently displayed sprite index 0xfd == custom sprite, 0xfe == custom second head sprite 0xff == res...
uint16_t cur_speed
current speed
bool IsFrontEngine() const
Check if the vehicle is a front engine.
bool IsWaitingForUnbunching() const
Check whether a vehicle inside a depot is waiting for unbunching.
Definition vehicle.cpp:2547
void SetNext(Vehicle *next)
Set the next vehicle of this vehicle.
Definition vehicle.cpp:2941
bool HandleBreakdown()
Handle all of the aspects of a vehicle breakdown This includes adding smoke and sounds,...
Definition vehicle.cpp:1348
uint8_t progress
The percentage (if divided by 256) this vehicle already crossed the tile unit.
uint8_t tick_counter
Increased by one for each tick.
virtual bool IsInDepot() const
Check whether the vehicle is in the depot.
TileIndex tile
Current tile index.
TileIndex dest_tile
Heading for this tile.
void UpdatePosition()
Update the position of the vehicle.
Definition vehicle.cpp:1674
StationID last_station_visited
The last station we stopped at.
void InvalidateNewGRFCacheOfChain()
Invalidates cached NewGRF variables of all vehicles in the chain (after the current vehicle).
void ShowVisualEffect() const
Draw visual effects (smoke and/or sparks) for a vehicle chain.
Definition vehicle.cpp:2791
Owner owner
Which company owns the vehicle?
bool NeedsAutomaticServicing() const
Checks if the current order should be interrupted for a service-in-depot order.
Definition vehicle.cpp:283
uint8_t running_ticks
Number of ticks this vehicle was not stopped this day.
@ CannotEnter
The vehicle cannot enter the tile.
Definition tile_cmd.h:26
@ EnteredWormhole
The vehicle either entered a bridge, tunnel or depot tile (this includes the last tile of the bridge/...
Definition tile_cmd.h:25
VehicleEnterTileStates VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y)
Call the tile callback function for a vehicle entering a tile.
Definition vehicle.cpp:1831
static bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
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
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:100
static constexpr uint TILE_SIZE
Tile size in world coordinates.
Definition tile_type.h:15
@ TunnelBridge
Tunnel entry/exit and bridge heads.
Definition tile_type.h:58
@ Station
A tile of a station or airport.
Definition tile_type.h:54
@ Road
A tile with road and/or tram tracks.
Definition tile_type.h:51
Definition of the game-calendar-timer.
Definition of the game-economy-timer.
TrackdirBits TrackStatusToTrackdirBits(TrackStatus ts)
Returns the present-trackdir-information of a TrackStatus.
Definition track_func.h:352
bool IsReversingRoadTrackdir(Trackdir dir)
Checks whether the trackdir means that we are reversing.
Definition track_func.h:673
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
bool IsStraightRoadTrackdir(Trackdir dir)
Checks whether the given trackdir is a straight road.
Definition track_func.h:684
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
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_CROSS
X-Y-axis cross.
Definition track_type.h:43
Trackdir
Enumeration for tracks and directions.
Definition track_type.h:66
@ TRACKDIR_RVREV_NE
(Road vehicle) reverse direction north-east
Definition track_type.h:74
@ TRACKDIR_LOWER_E
Lower track and direction to east.
Definition track_type.h:71
@ TRACKDIR_RIGHT_N
Right track and direction to north.
Definition track_type.h:81
@ INVALID_TRACKDIR
Flag for an invalid trackdir.
Definition track_type.h:85
@ TRACKDIR_UPPER_E
Upper track and direction to east.
Definition track_type.h:70
@ TRACKDIR_LEFT_S
Left track and direction to south.
Definition track_type.h:72
@ TRACKDIR_UPPER_W
Upper track and direction to west.
Definition track_type.h:78
@ TRACKDIR_RVREV_SE
(Road vehicle) reverse direction south-east
Definition track_type.h:75
@ TRACKDIR_LOWER_W
Lower track and direction to west.
Definition track_type.h:79
@ TRACKDIR_END
Used for iterations.
Definition track_type.h:84
@ TRACKDIR_RIGHT_S
Right track and direction to south.
Definition track_type.h:73
@ TRACKDIR_RVREV_NW
(Road vehicle) reverse direction north-west
Definition track_type.h:83
@ TRACKDIR_RVREV_SW
(Road vehicle) reverse direction south-west
Definition track_type.h:82
@ TRACKDIR_LEFT_N
Left track and direction to north.
Definition track_type.h:80
TrackdirBits
Allow incrementing of Trackdir variables.
Definition track_type.h:97
@ TRACKDIR_BIT_NONE
No track build.
Definition track_type.h:98
@ TRANSPORT_ROAD
Transport by road vehicle.
Functions that have tunnels and bridges in common.
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 VehicleEnterDepot(Vehicle *v)
Vehicle entirely entered the depot, update its status, orders, vehicle windows, service it,...
Definition vehicle.cpp:1536
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:354
void VehicleServiceInDepot(Vehicle *v)
Service a vehicle and all subsequent vehicles in the consist.
Definition vehicle.cpp:178
void CheckVehicleBreakdown(Vehicle *v)
Periodic check for a vehicle to maybe break down.
Definition vehicle.cpp:1292
GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
Get position information of a vehicle when moving one pixel in the direction it is facing.
Definition vehicle.cpp:1777
void DecreaseVehicleValue(Vehicle *v)
Decrease the value of a vehicle.
Definition vehicle.cpp:1271
void EconomyAgeVehicle(Vehicle *v)
Update economy age of a vehicle.
Definition vehicle.cpp:1414
bool CanVehicleUseStation(EngineID engine_type, const Station *st)
Can this station be used by the given engine type?
Definition vehicle.cpp:3060
void AgeVehicle(Vehicle *v)
Update age of a vehicle.
Definition vehicle.cpp:1426
@ Crashed
Vehicle is crashed.
@ Hidden
Vehicle is not visible.
@ DefaultPalette
Use default vehicle palette.
@ Stopped
Vehicle is stopped by the player.
Functions related to vehicles.
bool HasVehicleNearTileXY(int32_t x, int32_t y, uint max_dist, UnaryPred &&predicate)
Loop over vehicles near a given world coordinate, and check whether a predicate is true for any of th...
bool IsValidImageIndex(uint8_t image_index)
Helper to check whether an image index is valid for a particular vehicle.
@ CUSTOM_VEHICLE_SPRITENUM_REVERSED
Vehicle sprite from NewGRF with reverse driving direction (from articulation callback).
bool HasVehicleOnTile(TileIndex tile, UnaryPred &&predicate)
Loop over vehicles on a tile, and check whether a predicate is true for any of them.
EngineImageType
Visualisation contexts of vehicles and engines.
PoolID< uint32_t, struct VehicleIDTag, 0xFF000, 0xFFFFF > VehicleID
The type all our vehicle IDs have.
@ VEH_ROAD
Road vehicle type.
static const uint VEHICLE_LENGTH
The length of a vehicle in tile units.
@ WID_VV_START_STOP
Start or stop this vehicle, and show information about the current state.
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting).
Definition window.cpp:3218
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:3310
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:3204
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting).
Definition window.cpp:3188
@ WC_ROADVEH_LIST
Road vehicle list; Window numbers:
@ WC_VEHICLE_DEPOT
Depot view; Window numbers:
@ WC_VEHICLE_DETAILS
Vehicle details; Window numbers:
@ WC_VEHICLE_VIEW
Vehicle view; Window numbers:
Entry point for OpenTTD to YAPF.
Trackdir YapfRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirs, bool &path_found, RoadVehPathCache &path_cache)
Finds the best path for given road vehicle using YAPF.
FindDepotData YapfRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_penalty)
Used when user sends road vehicle to the nearest depot or if road vehicle needs servicing using 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