OpenTTD Source 20260108-master-g8ba1860eaa
articulated_vehicles.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
10#include "stdafx.h"
11#include "core/bitmath_func.hpp"
12#include "core/random_func.hpp"
13#include "train.h"
14#include "roadveh.h"
15#include "vehicle_func.h"
16#include "engine_func.h"
17#include "company_func.h"
18#include "newgrf.h"
19
20#include "table/strings.h"
21
22#include "safeguards.h"
23
24static const uint MAX_ARTICULATED_PARTS = 100;
25
34static EngineID GetNextArticulatedPart(uint index, EngineID front_type, Vehicle *front = nullptr, bool *mirrored = nullptr)
35{
36 assert(front == nullptr || front->engine_type == front_type);
37
38 const Engine *front_engine = Engine::Get(front_type);
39
40 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, index, 0, front_type, front);
41 if (callback == CALLBACK_FAILED) return EngineID::Invalid();
42
43 if (front_engine->GetGRF()->grf_version < 8) {
44 /* 8 bits, bit 7 for mirroring */
45 callback = GB(callback, 0, 8);
46 if (callback == 0xFF) return EngineID::Invalid();
47 if (mirrored != nullptr) *mirrored = HasBit(callback, 7);
48 callback = GB(callback, 0, 7);
49 } else {
50 /* 15 bits, bit 14 for mirroring */
51 if (callback == 0x7FFF) return EngineID::Invalid();
52 if (mirrored != nullptr) *mirrored = HasBit(callback, 14);
53 callback = GB(callback, 0, 14);
54 }
55
56 return GetNewEngineID(front_engine->GetGRF(), front_engine->type, callback);
57}
58
65{
66 return EngInfo(engine_type)->callback_mask.Test(VehicleCallbackMask::ArticEngine);
67}
68
75{
76 if (!EngInfo(engine_type)->callback_mask.Test(VehicleCallbackMask::ArticEngine)) return 0;
77
78 Vehicle v(VehicleID::Invalid());
79 v.engine_type = engine_type;
81
82 uint i;
83 for (i = 1; i < MAX_ARTICULATED_PARTS; i++) {
84 if (GetNextArticulatedPart(i, engine_type, &v) == EngineID::Invalid()) break;
85 }
86
87 return i - 1;
88}
89
90
96static inline std::pair<CargoType, uint16_t> GetVehicleDefaultCapacity(EngineID engine)
97{
98 const Engine *e = Engine::Get(engine);
99 CargoType cargo = e->CanCarryCargo() ? e->GetDefaultCargoType() : INVALID_CARGO;
100 return {cargo, IsValidCargoType(cargo) ? e->GetDisplayDefaultCapacity() : 0};
101}
102
109static inline CargoTypes GetAvailableVehicleCargoTypes(EngineID engine, bool include_initial_cargo_type)
110{
111 const Engine *e = Engine::Get(engine);
112 if (!e->CanCarryCargo()) return 0;
113
114 CargoTypes cargoes = e->info.refit_mask;
115
116 if (include_initial_cargo_type) {
117 SetBit(cargoes, e->GetDefaultCargoType());
118 }
119
120 return cargoes;
121}
122
129{
130 CargoArray capacity{};
131 const Engine *e = Engine::Get(engine);
132
133 if (auto [cargo, cap] = GetVehicleDefaultCapacity(engine); IsValidCargoType(cargo)) {
134 capacity[cargo] = cap;
135 }
136
137 if (!e->IsGroundVehicle()) return capacity;
138
139 if (!e->info.callback_mask.Test(VehicleCallbackMask::ArticEngine)) return capacity;
140
141 for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
142 EngineID artic_engine = GetNextArticulatedPart(i, engine);
143 if (artic_engine == EngineID::Invalid()) break;
144
145 if (auto [cargo, cap] = GetVehicleDefaultCapacity(artic_engine); IsValidCargoType(cargo)) {
146 capacity[cargo] += cap;
147 }
148 }
149
150 return capacity;
151}
152
159{
160 CargoTypes cargoes = 0;
161 const Engine *e = Engine::Get(engine);
162
163 if (auto [cargo, cap] = GetVehicleDefaultCapacity(engine); IsValidCargoType(cargo) && cap > 0) {
164 SetBit(cargoes, cargo);
165 }
166
167 if (!e->IsGroundVehicle()) return cargoes;
168
169 if (!e->info.callback_mask.Test(VehicleCallbackMask::ArticEngine)) return cargoes;
170
171 for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
172 EngineID artic_engine = GetNextArticulatedPart(i, engine);
173 if (artic_engine == EngineID::Invalid()) break;
174
175 if (auto [cargo, cap] = GetVehicleDefaultCapacity(artic_engine); IsValidCargoType(cargo) && cap > 0) {
176 SetBit(cargoes, cargo);
177 }
178 }
179
180 return cargoes;
181}
182
189{
190 if (IsEngineRefittable(engine)) return true;
191
192 const Engine *e = Engine::Get(engine);
193 if (!e->IsGroundVehicle()) return false;
194
195 if (!e->info.callback_mask.Test(VehicleCallbackMask::ArticEngine)) return false;
196
197 for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
198 EngineID artic_engine = GetNextArticulatedPart(i, engine);
199 if (artic_engine == EngineID::Invalid()) break;
200
201 if (IsEngineRefittable(artic_engine)) return true;
202 }
203
204 return false;
205}
206
214void GetArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type, CargoTypes *union_mask, CargoTypes *intersection_mask)
215{
216 const Engine *e = Engine::Get(engine);
217 CargoTypes veh_cargoes = GetAvailableVehicleCargoTypes(engine, include_initial_cargo_type);
218 *union_mask = veh_cargoes;
219 *intersection_mask = (veh_cargoes != 0) ? veh_cargoes : ALL_CARGOTYPES;
220
221 if (!e->IsGroundVehicle()) return;
223
224 for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
225 EngineID artic_engine = GetNextArticulatedPart(i, engine);
226 if (artic_engine == EngineID::Invalid()) break;
227
228 veh_cargoes = GetAvailableVehicleCargoTypes(artic_engine, include_initial_cargo_type);
229 *union_mask |= veh_cargoes;
230 if (veh_cargoes != 0) *intersection_mask &= veh_cargoes;
231 }
232}
233
240CargoTypes GetUnionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type)
241{
242 CargoTypes union_mask, intersection_mask;
243 GetArticulatedRefitMasks(engine, include_initial_cargo_type, &union_mask, &intersection_mask);
244 return union_mask;
245}
246
254CargoTypes GetCargoTypesOfArticulatedVehicle(const Vehicle *v, CargoType *cargo_type)
255{
256 CargoTypes cargoes = 0;
257 CargoType first_cargo = INVALID_CARGO;
258
259 do {
261 SetBit(cargoes, v->cargo_type);
262 if (!IsValidCargoType(first_cargo)) first_cargo = v->cargo_type;
263 if (first_cargo != v->cargo_type) {
264 if (cargo_type != nullptr) {
265 *cargo_type = INVALID_CARGO;
266 cargo_type = nullptr;
267 }
268 }
269 }
270
271 v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : nullptr;
272 } while (v != nullptr);
273
274 if (cargo_type != nullptr) *cargo_type = first_cargo;
275 return cargoes;
276}
277
287{
288 const Engine *engine = v->GetEngine();
289
290 CargoTypes purchase_refit_union, purchase_refit_intersection;
291 GetArticulatedRefitMasks(v->engine_type, true, &purchase_refit_union, &purchase_refit_intersection);
292 CargoArray purchase_default_capacity = GetCapacityOfArticulatedParts(v->engine_type);
293
294 CargoTypes real_refit_union = 0;
295 CargoTypes real_refit_intersection = ALL_CARGOTYPES;
296 CargoTypes real_default_cargoes = 0;
297
298 do {
299 CargoTypes refit_mask = GetAvailableVehicleCargoTypes(v->engine_type, true);
300 real_refit_union |= refit_mask;
301 if (refit_mask != 0) real_refit_intersection &= refit_mask;
302
303 assert(v->cargo_type < NUM_CARGO);
304 if (v->cargo_cap > 0) SetBit(real_default_cargoes, v->cargo_type);
305
306 v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : nullptr;
307 } while (v != nullptr);
308
309 /* Check whether the vehicle carries more cargoes than expected */
310 bool carries_more = false;
311 for (CargoType cargo_type : SetCargoBitIterator(real_default_cargoes)) {
312 if (purchase_default_capacity[cargo_type] == 0) {
313 carries_more = true;
314 break;
315 }
316 }
317
318 /* show a warning once for each GRF after each game load */
319 if (real_refit_union != purchase_refit_union || real_refit_intersection != purchase_refit_intersection || carries_more) {
320 ShowNewGrfVehicleError(engine->index, STR_NEWGRF_BUGGY, STR_NEWGRF_BUGGY_ARTICULATED_CARGO, GRFBug::VehRefit, false);
321 }
322}
323
329{
330 VehicleType type = first->type;
331 if (!EngInfo(first->engine_type)->callback_mask.Test(VehicleCallbackMask::ArticEngine)) return;
332
333 Vehicle *v = first;
334 for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) {
335 bool flip_image;
336 EngineID engine_type = GetNextArticulatedPart(i, first->engine_type, first, &flip_image);
337 if (engine_type == EngineID::Invalid()) return;
338
339 /* In the (very rare) case the GRF reported wrong number of articulated parts
340 * and we run out of available vehicles, bail out. */
341 if (!Vehicle::CanAllocateItem()) return;
342
344 gcache->first_engine = v->engine_type; // Needs to be set before first callback
345
346 const Engine *e_artic = Engine::Get(engine_type);
347 switch (type) {
348 default: NOT_REACHED();
349
350 case VEH_TRAIN: {
351 Train *front = Train::From(first);
352 Train *t = Train::Create();
353 v->SetNext(t);
354 v = t;
355
356 t->subtype = 0;
357 t->track = front->track;
358 t->railtypes = front->railtypes;
359
360 t->spritenum = e_artic->VehInfo<RailVehicleInfo>().image_index;
361 if (e_artic->CanCarryCargo()) {
362 t->cargo_type = e_artic->GetDefaultCargoType();
363 t->cargo_cap = e_artic->VehInfo<RailVehicleInfo>().capacity; // Callback 36 is called when the consist is finished
364 } else {
365 t->cargo_type = front->cargo_type; // Needed for livery selection
366 t->cargo_cap = 0;
367 }
368 t->refit_cap = 0;
369
371 break;
372 }
373
374 case VEH_ROAD: {
375 RoadVehicle *front = RoadVehicle::From(first);
377 v->SetNext(rv);
378 v = rv;
379
380 rv->subtype = 0;
381 gcache->cached_veh_length = VEHICLE_LENGTH; // Callback is called when the consist is finished
382 rv->state = RVSB_IN_DEPOT;
383
384 rv->roadtype = front->roadtype;
386
387 rv->spritenum = e_artic->VehInfo<RoadVehicleInfo>().image_index;
388 if (e_artic->CanCarryCargo()) {
389 rv->cargo_type = e_artic->GetDefaultCargoType();
390 assert(IsValidCargoType(rv->cargo_type));
391 rv->cargo_cap = e_artic->VehInfo<RoadVehicleInfo>().capacity; // Callback 36 is called when the consist is finished
392 } else {
393 rv->cargo_type = front->cargo_type; // Needed for livery selection
394 rv->cargo_cap = 0;
395 }
396 rv->refit_cap = 0;
397
398 rv->SetArticulatedPart();
399 break;
400 }
401 }
402
403 /* get common values from first engine */
404 v->direction = first->direction;
405 v->owner = first->owner;
406 v->tile = first->tile;
407 v->x_pos = first->x_pos;
408 v->y_pos = first->y_pos;
409 v->z_pos = first->z_pos;
412 v->build_year = first->build_year;
413 v->vehstatus = first->vehstatus;
415
416 v->cargo_subtype = 0;
418 v->engine_type = engine_type;
419 v->value = 0;
420 v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
421 v->random_bits = Random();
422
423 if (flip_image) v->spritenum++;
424
425 if (v->type == VEH_TRAIN) {
426 auto prob = TestVehicleBuildProbability(v, v->engine_type, BuildProbabilityType::Reversed);
427 if (prob.has_value()) Train::From(v)->flags.Set(VehicleRailFlag::Flipped, prob.value());
428 }
429 v->UpdatePosition();
430 }
431}
CargoTypes GetUnionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type)
Ors the refit_masks of all articulated parts.
bool IsArticulatedEngine(EngineID engine_type)
Does a NewGRF report that this should be an articulated vehicle?
static const uint MAX_ARTICULATED_PARTS
Maximum of articulated parts per vehicle, i.e. when to abort calling the articulated vehicle callback...
void AddArticulatedParts(Vehicle *first)
Add the remaining articulated parts to the given vehicle.
CargoArray GetCapacityOfArticulatedParts(EngineID engine)
Get the capacity of the parts of a given engine.
bool IsArticulatedVehicleRefittable(EngineID engine)
Checks whether any of the articulated parts is refittable.
CargoTypes GetCargoTypesOfArticulatedVehicle(const Vehicle *v, CargoType *cargo_type)
Get cargo mask of all cargoes carried by an articulated vehicle.
static std::pair< CargoType, uint16_t > GetVehicleDefaultCapacity(EngineID engine)
Returns the default (non-refitted) cargo and capacity of a specific EngineID.
void GetArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type, CargoTypes *union_mask, CargoTypes *intersection_mask)
Merges the refit_masks of all articulated parts.
uint CountArticulatedParts(EngineID engine_type)
Count the number of articulated parts of an engine.
void CheckConsistencyOfArticulatedVehicle(const Vehicle *v)
Checks whether the specs of freshly build articulated vehicles are consistent with the information sp...
CargoTypes GetCargoTypesOfArticulatedParts(EngineID engine)
Get the cargo mask of the parts of a given engine.
static EngineID GetNextArticulatedPart(uint index, EngineID front_type, Vehicle *front=nullptr, bool *mirrored=nullptr)
Determines the next articulated part to attach.
static CargoTypes GetAvailableVehicleCargoTypes(EngineID engine, bool include_initial_cargo_type)
Returns all cargoes a vehicle can carry.
Functions related to bit mathematics.
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:21
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:104
static const CargoType NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:73
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Reset()
Reset all bits.
const GRFFile * GetGRF() const
Retrieve the NewGRF the engine is tied to.
VehicleType type
Vehicle type, ie VEH_ROAD, VEH_TRAIN, etc.
Definition engine_base.h:62
uint GetDisplayDefaultCapacity(uint16_t *mail_capacity=nullptr) const
Determines the default cargo capacity of an engine for display purposes.
CargoType GetDefaultCargoType() const
Determines the default cargo type of an engine.
Definition engine_base.h:94
bool CanCarryCargo() const
Determines whether an engine can carry something.
Definition engine.cpp:171
bool IsGroundVehicle() const
Check if the engine is a ground vehicle.
static constexpr TimerGame< struct Calendar >::Date MIN_DATE
The date on January 1, year 0.
CompanyID _current_company
Company currently doing an action.
Functions related to companies.
bool IsEngineRefittable(EngineID engine)
Check if an engine is refittable.
Definition engine.cpp:1291
Functions related to engines.
@ Random
Randomise borders.
EngineID GetNewEngineID(const GRFFile *file, VehicleType type, uint16_t internal_id)
Return the ID of a new engine.
Definition newgrf.cpp:296
Base for the NewGRF implementation.
@ ArticEngine
Add articulated engines (trains and road vehicles)
@ CBID_VEHICLE_ARTIC_ENGINE
Builds articulated engines for trains and RVs.
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
@ VehRefit
Articulated vehicles carry different cargoes resp. are differently refittable than specified in purch...
std::optional< bool > TestVehicleBuildProbability(Vehicle *v, EngineID engine, BuildProbabilityType type)
Test for vehicle build probability type.
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.
Pseudo random number generator.
Road vehicle states.
@ RVSB_IN_DEPOT
The vehicle is in a depot.
Definition roadveh.h:38
A number of safeguards to prevent using unsafe methods.
Definition of base types and functions in a cross-platform compatible way.
VehicleType type
Type of vehicle.
Class for storing amounts of cargo.
Definition cargo_type.h:111
VehicleCallbackMasks callback_mask
Bitmask of vehicle callbacks that have to be called.
Cached, frequently calculated values.
EngineID first_engine
Cached EngineID of the front vehicle. EngineID::Invalid() for the front vehicle itself.
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...
void SetArticulatedPart()
Set a vehicle to be an articulated part.
VehicleSpriteSeq sprite_seq
Vehicle appearance.
static Titem * Get(auto index)
Returns Titem with given index.
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
const Tindex index
Index of this pool item.
Information about a rail vehicle.
Definition engine_type.h:74
Information about a road vehicle.
Buses, trucks and trams belong to this class.
Definition roadveh.h:98
uint8_t state
Definition roadveh.h:100
RoadTypes compatible_roadtypes
NOSAVE: Roadtypes this consist is powered on.
Definition roadveh.h:110
RoadType roadtype
NOSAVE: Roadtype of this vehicle.
Definition roadveh.h:108
Iterable ensemble of each set bit in a value.
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
static T * Create(Targs &&... args)
Creates a new T-object in the vehicle pool.
'Train' is either a loco or a wagon.
Definition train.h:91
void Set(SpriteID sprite)
Assign a single sprite to the sequence.
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
Vehicle * GetNextArticulatedPart() const
Get the next part of an articulated engine.
TimerGameEconomy::Date date_of_last_service
Last economy date the vehicle had a service at a depot.
uint16_t cargo_cap
total capacity
uint8_t subtype
subtype (Filled with values from AircraftSubType/DisasterSubType/EffectVehicleType/GroundVehicleSubty...
uint16_t random_bits
Bits used for randomized variational spritegroups.
bool HasArticulatedPart() const
Check if an engine has an articulated part.
VehStates vehstatus
Status.
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...
CargoType cargo_type
type of cargo this vehicle is carrying
int32_t y_pos
y coordinate.
int32_t x_pos
x coordinate.
Money value
Value of the vehicle.
uint16_t refit_cap
Capacity left over from before last refit.
GroundVehicleCache * GetGroundVehicleCache()
Access the ground vehicle cache of the vehicle.
Definition vehicle.cpp:3144
uint8_t spritenum
currently displayed sprite index 0xfd == custom sprite, 0xfe == custom second head sprite 0xff == res...
uint8_t cargo_subtype
Used for livery refits (NewGRF variations)
void SetNext(Vehicle *next)
Set the next vehicle of this vehicle.
Definition vehicle.cpp:2928
TimerGameCalendar::Date max_age
Maximum age.
MutableSpriteCache sprite_cache
Cache of sprites and values related to recalculating them, see MutableSpriteCache.
TileIndex tile
Current tile index.
void UpdatePosition()
Update the position of the vehicle.
Definition vehicle.cpp:1663
TimerGameCalendar::Year build_year
Year the vehicle has been built.
Owner owner
Which company owns the vehicle?
Base for the train class.
@ Flipped
Reverse the visible direction of the vehicle.
Definition train.h:28
void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBug bug_type, bool critical)
Displays a "NewGrf Bug" error message for a engine, and pauses the game if not networking.
Definition vehicle.cpp:328
@ Stopped
Vehicle is stopped by the player.
Functions related to vehicles.
VehicleType
Available vehicle types.
@ VEH_ROAD
Road vehicle type.
@ VEH_TRAIN
Train vehicle type.
static const uint VEHICLE_LENGTH
The length of a vehicle in tile units.