OpenTTD Source 20260512-master-g20b387b91f
engine.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"
12#include "company_func.h"
13#include "command_func.h"
14#include "news_func.h"
15#include "aircraft.h"
16#include "newgrf.h"
17#include "newgrf_engine.h"
18#include "strings_func.h"
19#include "core/random_func.hpp"
20#include "window_func.h"
21#include "autoreplace_gui.h"
22#include "string_func.h"
23#include "ai/ai.hpp"
24#include "core/pool_func.hpp"
25#include "engine_gui.h"
26#include "engine_func.h"
27#include "engine_base.h"
28#include "company_base.h"
29#include "vehicle_func.h"
31#include "error.h"
32#include "engine_base.h"
33#include "timer/timer.h"
36
37#include "table/strings.h"
38#include "table/engines.h"
39
40#include "safeguards.h"
41
42EnginePool _engine_pool("Engine");
44
45EngineOverrideManager _engine_mngr;
46
52
59{
61 static constexpr VehicleTypeIndexArray<uint8_t> ENGINE_COUNTS = {
62 lengthof(_orig_rail_vehicle_info),
63 lengthof(_orig_road_vehicle_info),
64 lengthof(_orig_ship_vehicle_info),
65 lengthof(_orig_aircraft_vehicle_info),
66 };
67
69 return ENGINE_COUNTS[type];
70}
71
78{
80 static constexpr VehicleTypeIndexArray<uint8_t> ENGINE_OFFSETS = {
81 0,
82 lengthof(_orig_rail_vehicle_info),
83 lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info),
84 lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info) + lengthof(_orig_ship_vehicle_info),
85 };
86
88 return ENGINE_OFFSETS[type];
89}
90
91static_assert(lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info) + lengthof(_orig_ship_vehicle_info) + lengthof(_orig_aircraft_vehicle_info) == lengthof(_orig_engine_info));
92
93Engine::Engine(EngineID index, VehicleType type, uint16_t local_id) : EnginePool::PoolItem<&_engine_pool>(index)
94{
95 this->type = type;
96
97 /* Called in the context of loading a savegame. The rest comes from the loader. */
98 if (type == VehicleType::Invalid) return;
99
100 this->grf_prop.local_id = local_id;
101 this->list_position = local_id;
102 this->preview_company = CompanyID::Invalid();
103 this->display_last_variant = EngineID::Invalid();
104
105 /* Check if this base engine is within the original engine data range */
106 if (local_id >= GetOriginalEngineCount(type)) {
107 /* Initialise default type-specific information. */
108 switch (type) {
109 case VehicleType::Train: this->vehicle_info.emplace<RailVehicleInfo>(); break;
110 case VehicleType::Road: this->vehicle_info.emplace<RoadVehicleInfo>(); break;
111 case VehicleType::Ship: this->vehicle_info.emplace<ShipVehicleInfo>(); break;
112 case VehicleType::Aircraft: this->vehicle_info.emplace<AircraftVehicleInfo>(); break;
113 default: break;
114 }
115 /* Set model life to maximum to make wagons available */
116 this->info.base_life = TimerGameCalendar::Year{0xFF};
117 /* Aircraft must have CT_INVALID as default, as there is no property */
118 this->info.cargo_type = INVALID_CARGO;
119 this->info.cargo_label = (type == VehicleType::Aircraft) ? CT_INVALID : CT_PASSENGERS;
120 /* Set cargo aging period to the default value. */
121 this->info.cargo_age_period = Ticks::CARGO_AGING_TICKS;
122 /* Not a variant */
123 this->info.variant_id = EngineID::Invalid();
124 return;
125 }
126
127 /* Copy the original engine info for this slot */
128 this->info = _orig_engine_info[GetOriginalEngineOffset(type) + local_id];
129
130 /* Copy the original engine data for this slot */
131 switch (type) {
132 default: NOT_REACHED();
133
134 case VehicleType::Train: {
135 RailVehicleInfo &rvi = this->vehicle_info.emplace<RailVehicleInfo>(_orig_rail_vehicle_info[local_id]);
136 this->original_image_index = rvi.image_index;
137 this->info.string_id = STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KIRBY_PAUL_TANK_STEAM + local_id;
138
139 /* Set the default model life of original wagons to "infinite" */
140 if (rvi.railveh_type == RailVehicleType::Wagon) this->info.base_life = TimerGameCalendar::Year{0xFF};
141
142 break;
143 }
144
145 case VehicleType::Road: {
146 RoadVehicleInfo &rvi = this->vehicle_info.emplace<RoadVehicleInfo>(_orig_road_vehicle_info[local_id]);
147 this->original_image_index = rvi.image_index;
148 this->info.string_id = STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_REGAL_BUS + local_id;
149 break;
150 }
151
152 case VehicleType::Ship: {
153 ShipVehicleInfo &svi = this->vehicle_info.emplace<ShipVehicleInfo>(_orig_ship_vehicle_info[local_id]);
154 this->original_image_index = svi.image_index;
155 this->info.string_id = STR_VEHICLE_NAME_SHIP_MPS_OIL_TANKER + local_id;
156 break;
157 }
158
160 AircraftVehicleInfo &avi = this->vehicle_info.emplace<AircraftVehicleInfo>(_orig_aircraft_vehicle_info[local_id]);
161 this->original_image_index = avi.image_index;
162 this->info.string_id = STR_VEHICLE_NAME_AIRCRAFT_SAMPSON_U52 + local_id;
163 break;
164 }
165 }
166}
167
173{
174 return this->info.string_id != STR_NEWGRF_INVALID_ENGINE && this->info.climates.Test(_settings_game.game_creation.landscape);
175}
176
182uint32_t Engine::GetGRFID() const
183{
184 const GRFFile *file = this->GetGRF();
185 return file == nullptr ? 0 : file->grfid;
186}
187
194{
195 /* For engines that can appear in a consist (i.e. rail vehicles and (articulated) road vehicles), a capacity
196 * of zero is a special case, to define the vehicle to not carry anything. The default cargotype is still used
197 * for livery selection etc.
198 * Note: Only the property is tested. A capacity callback returning 0 does not have the same effect.
199 */
200 switch (this->type) {
202 if (this->VehInfo<RailVehicleInfo>().capacity == 0) return false;
203 break;
204
206 if (this->VehInfo<RoadVehicleInfo>().capacity == 0) return false;
207 break;
208
211 break;
212
213 default: NOT_REACHED();
214 }
216}
217
218
226uint Engine::DetermineCapacity(const Vehicle *v, uint16_t *mail_capacity) const
227{
228 assert(v == nullptr || this->index == v->engine_type);
229 if (mail_capacity != nullptr) *mail_capacity = 0;
230
231 if (!this->CanCarryCargo()) return 0;
232
233 bool new_multipliers = this->info.misc_flags.Test(EngineMiscFlag::NoDefaultCargoMultiplier);
234 CargoType default_cargo = this->GetDefaultCargoType();
235 CargoType cargo_type = (v != nullptr) ? v->cargo_type : default_cargo;
236
237 if (mail_capacity != nullptr && this->type == VehicleType::Aircraft && IsCargoInClass(cargo_type, CargoClass::Passengers)) {
238 *mail_capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->VehInfo<AircraftVehicleInfo>().mail_capacity, v);
239 }
240
241 /* Check the refit capacity callback if we are not in the default configuration, or if we are using the new multiplier algorithm. */
242 if (this->info.callback_mask.Test(VehicleCallbackMask::RefitCapacity) &&
243 (new_multipliers || default_cargo != cargo_type || (v != nullptr && v->cargo_subtype != 0))) {
244 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, this->index, v);
245 if (callback != CALLBACK_FAILED) return callback;
246 }
247
248 /* Get capacity according to property resp. CB */
249 uint capacity;
250 uint extra_mail_cap = 0;
251 switch (this->type) {
253 capacity = GetEngineProperty(this->index, PROP_TRAIN_CARGO_CAPACITY, this->VehInfo<RailVehicleInfo>().capacity, v);
254
255 /* In purchase list add the capacity of the second head. Always use the plain property for this. */
256 if (v == nullptr && this->VehInfo<RailVehicleInfo>().railveh_type == RailVehicleType::Multihead) capacity += this->VehInfo<RailVehicleInfo>().capacity;
257 break;
258
260 capacity = GetEngineProperty(this->index, PROP_ROADVEH_CARGO_CAPACITY, this->VehInfo<RoadVehicleInfo>().capacity, v);
261 break;
262
264 capacity = GetEngineProperty(this->index, PROP_SHIP_CARGO_CAPACITY, this->VehInfo<ShipVehicleInfo>().capacity, v);
265 break;
266
268 capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_PASSENGER_CAPACITY, this->VehInfo<AircraftVehicleInfo>().passenger_capacity, v);
269 if (!IsCargoInClass(cargo_type, CargoClass::Passengers)) {
270 extra_mail_cap = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->VehInfo<AircraftVehicleInfo>().mail_capacity, v);
271 }
272 if (IsValidCargoType(GetCargoTypeByLabel(CT_MAIL))) {
273 if (!new_multipliers && cargo_type == GetCargoTypeByLabel(CT_MAIL)) return capacity + extra_mail_cap;
274 }
275 default_cargo = GetCargoTypeByLabel(CT_PASSENGERS); // Always use 'passengers' wrt. cargo multipliers
276 break;
277
278 default: NOT_REACHED();
279 }
280
281 if (!new_multipliers) {
282 /* Use the passenger multiplier for mail as well */
283 capacity += extra_mail_cap;
284 extra_mail_cap = 0;
285 }
286
287 /* Apply multipliers depending on cargo- and vehicletype. */
288 if (new_multipliers || (this->type != VehicleType::Ship && default_cargo != cargo_type)) {
289 uint16_t default_multiplier = new_multipliers ? 0x100 : CargoSpec::Get(default_cargo)->multiplier;
290 uint16_t cargo_multiplier = CargoSpec::Get(cargo_type)->multiplier;
291 capacity *= cargo_multiplier;
292 if (extra_mail_cap > 0 && IsValidCargoType(GetCargoTypeByLabel(CT_MAIL))) {
293 uint mail_multiplier = CargoSpec::Get(GetCargoTypeByLabel(CT_MAIL))->multiplier;
294 capacity += (default_multiplier * extra_mail_cap * cargo_multiplier + mail_multiplier / 2) / mail_multiplier;
295 }
296 capacity = (capacity + default_multiplier / 2) / default_multiplier;
297 }
298
299 return capacity;
300}
301
307{
308 Price base_price;
309 uint cost_factor;
310 switch (this->type) {
312 base_price = this->VehInfo<RoadVehicleInfo>().running_cost_class;
313 if (base_price == Price::Invalid) return 0;
314 cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_RUNNING_COST_FACTOR, this->VehInfo<RoadVehicleInfo>().running_cost);
315 break;
316
318 base_price = this->VehInfo<RailVehicleInfo>().running_cost_class;
319 if (base_price == Price::Invalid) return 0;
320 cost_factor = GetEngineProperty(this->index, PROP_TRAIN_RUNNING_COST_FACTOR, this->VehInfo<RailVehicleInfo>().running_cost);
321 break;
322
324 base_price = Price::RunningShip;
325 cost_factor = GetEngineProperty(this->index, PROP_SHIP_RUNNING_COST_FACTOR, this->VehInfo<ShipVehicleInfo>().running_cost);
326 break;
327
329 base_price = Price::RunningAircraft;
330 cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_RUNNING_COST_FACTOR, this->VehInfo<AircraftVehicleInfo>().running_cost);
331 break;
332
333 default: NOT_REACHED();
334 }
335
336 return GetPrice(base_price, cost_factor, this->GetGRF(), -8);
337}
338
343Money Engine::GetCost() const
344{
345 Price base_price;
346 uint cost_factor;
347 switch (this->type) {
349 base_price = Price::BuildVehicleRoad;
350 cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_COST_FACTOR, this->VehInfo<RoadVehicleInfo>().cost_factor);
351 break;
352
354 if (this->VehInfo<RailVehicleInfo>().railveh_type == RailVehicleType::Wagon) {
355 base_price = Price::BuildVehicleWagon;
356 cost_factor = GetEngineProperty(this->index, PROP_TRAIN_COST_FACTOR, this->VehInfo<RailVehicleInfo>().cost_factor);
357 } else {
358 base_price = Price::BuildVehicleTrain;
359 cost_factor = GetEngineProperty(this->index, PROP_TRAIN_COST_FACTOR, this->VehInfo<RailVehicleInfo>().cost_factor);
360 }
361 break;
362
364 base_price = Price::BuildVehicleShip;
365 cost_factor = GetEngineProperty(this->index, PROP_SHIP_COST_FACTOR, this->VehInfo<ShipVehicleInfo>().cost_factor);
366 break;
367
369 base_price = Price::BuildVehicleAircraft;
370 cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_COST_FACTOR, this->VehInfo<AircraftVehicleInfo>().cost_factor);
371 break;
372
373 default: NOT_REACHED();
374 }
375
376 return GetPrice(base_price, cost_factor, this->GetGRF(), -8);
377}
378
384{
385 switch (this->type) {
387 return GetEngineProperty(this->index, PROP_TRAIN_SPEED, this->VehInfo<RailVehicleInfo>().max_speed);
388
389 case VehicleType::Road: {
390 uint max_speed = GetEngineProperty(this->index, PROP_ROADVEH_SPEED, 0);
391 return (max_speed != 0) ? max_speed * 2 : this->VehInfo<RoadVehicleInfo>().max_speed / 2;
392 }
393
395 return GetEngineProperty(this->index, PROP_SHIP_SPEED, this->VehInfo<ShipVehicleInfo>().max_speed) / 2;
396
398 uint max_speed = GetEngineProperty(this->index, PROP_AIRCRAFT_SPEED, 0);
399 if (max_speed != 0) {
400 return (max_speed * 128) / 10;
401 }
402 return this->VehInfo<AircraftVehicleInfo>().max_speed;
403 }
404
405 default: NOT_REACHED();
406 }
407}
408
416{
417 /* Only trains and road vehicles have 'power'. */
418 switch (this->type) {
420 return GetEngineProperty(this->index, PROP_TRAIN_POWER, this->VehInfo<RailVehicleInfo>().power);
422 return GetEngineProperty(this->index, PROP_ROADVEH_POWER, this->VehInfo<RoadVehicleInfo>().power) * 10;
423
424 default: NOT_REACHED();
425 }
426}
427
434{
435 /* Only trains and road vehicles have 'weight'. */
436 switch (this->type) {
438 return GetEngineProperty(this->index, PROP_TRAIN_WEIGHT, this->VehInfo<RailVehicleInfo>().weight) << (this->VehInfo<RailVehicleInfo>().railveh_type == RailVehicleType::Multihead ? 1 : 0);
440 return GetEngineProperty(this->index, PROP_ROADVEH_WEIGHT, this->VehInfo<RoadVehicleInfo>().weight) / 4;
441
442 default: NOT_REACHED();
443 }
444}
445
452{
453 /* Only trains and road vehicles have 'tractive effort'. */
454 switch (this->type) {
456 return (GROUND_ACCELERATION * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_TRAIN_TRACTIVE_EFFORT, this->VehInfo<RailVehicleInfo>().tractive_effort)) / 256;
458 return (GROUND_ACCELERATION * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_ROADVEH_TRACTIVE_EFFORT, this->VehInfo<RoadVehicleInfo>().tractive_effort)) / 256;
459
460 default: NOT_REACHED();
461 }
462}
463
469{
470 /* Assume leap years; this gives the player a bit more than the given amount of years, but never less. */
471 return TimerGameCalendar::Date{(this->info.lifelength + _settings_game.vehicle.extend_vehicle_life).base() * CalendarTime::DAYS_IN_LEAP_YEAR};
472}
473
478uint16_t Engine::GetRange() const
479{
480 if (!_settings_game.vehicle.aircraft_range) return 0;
481 switch (this->type) {
483 return GetEngineProperty(this->index, PROP_AIRCRAFT_RANGE, this->VehInfo<AircraftVehicleInfo>().max_range);
484
485 default: NOT_REACHED();
486 }
487}
488
494{
495 switch (this->type) {
497 switch (this->VehInfo<AircraftVehicleInfo>().subtype) {
498 case AIR_HELI: return STR_LIVERY_HELICOPTER;
499 case AIR_CTOL: return STR_LIVERY_SMALL_PLANE;
500 case AIR_CTOL | AIR_FAST: return STR_LIVERY_LARGE_PLANE;
501 default: NOT_REACHED();
502 }
503
504 default: NOT_REACHED();
505 }
506}
507
513bool Engine::IsVariantHidden(CompanyID c) const
514{
515 /* In case company is spectator. */
516 if (c >= MAX_COMPANIES) return false;
517
518 /* Shortcut if this engine is explicitly hidden. */
519 if (this->IsHidden(c)) return true;
520
521 /* Check for hidden parent variants. This is a bit convoluted as we must check hidden status of
522 * the last display variant rather than the actual parent variant. */
523 const Engine *re = this;
524 const Engine *ve = re->GetDisplayVariant();
525 while (!(ve->IsHidden(c)) && re->info.variant_id != EngineID::Invalid()) {
526 re = Engine::Get(re->info.variant_id);
527 ve = re->GetDisplayVariant();
528 }
529 return ve->IsHidden(c);
530}
531
536{
537 EngineID id = EngineID::Begin();
538 for (VehicleType type = VehicleType::Train; type <= VehicleType::Aircraft; type++) {
539 auto &map = this->mappings[type];
540 map.clear();
541 for (uint internal_id = 0; internal_id < GetOriginalEngineCount(type); internal_id++, ++id) {
542 map.emplace_back(INVALID_GRFID, internal_id, type, internal_id, id);
543 }
544 }
545}
546
556EngineID EngineOverrideManager::GetID(VehicleType type, uint16_t grf_local_id, uint32_t grfid)
557{
558 const auto &map = this->mappings[type];
559 const auto key = EngineIDMapping::Key(grfid, grf_local_id);
560 auto it = std::ranges::lower_bound(map, key, std::less{}, EngineIDMappingKeyProjection{});
561 if (it == std::end(map) || it->Key() != key) return EngineID::Invalid();
562 return it->engine;
563}
564
575EngineID EngineOverrideManager::UseUnreservedID(VehicleType type, uint16_t grf_local_id, uint32_t grfid, bool static_access)
576{
577 auto &map = _engine_mngr.mappings[type];
578 const auto key = EngineIDMapping::Key(INVALID_GRFID, grf_local_id);
579 auto it = std::ranges::lower_bound(map, key, std::less{}, EngineIDMappingKeyProjection{});
580 if (it == std::end(map) || it->Key() != key) return EngineID::Invalid();
581
582 if (!static_access && grfid != INVALID_GRFID) {
583 /* Reserve the engine slot for the new grfid. */
584 it->grfid = grfid;
585
586 /* Relocate entry to its new position in the mapping list to keep it sorted. */
587 auto p = std::ranges::lower_bound(map, EngineIDMapping::Key(grfid, grf_local_id), std::less{}, EngineIDMappingKeyProjection{});
588 it = Slide(it, std::next(it), p).first;
589 }
590
591 return it->engine;
592}
593
594void EngineOverrideManager::SetID(VehicleType type, uint16_t grf_local_id, uint32_t grfid, uint8_t substitute_id, EngineID engine)
595{
596 auto &map = this->mappings[type];
597 const auto key = EngineIDMapping::Key(grfid, grf_local_id);
598 auto it = std::ranges::lower_bound(map, key, std::less{}, EngineIDMappingKeyProjection{});
599 if (it == std::end(map) || it->Key() != key) {
600 map.emplace(it, grfid, grf_local_id, type, substitute_id, engine);
601 } else {
602 it->engine = engine;
603 }
604}
605
612{
613 for (const Vehicle *v : Vehicle::Iterate()) {
614 if (IsCompanyBuildableVehicleType(v)) return false;
615 }
616
617 /* Reset the engines, they will get new EngineIDs */
618 _engine_mngr.ResetToDefaultMapping();
620
621 return true;
622}
623
628{
630 _engine_pool.CleanPool();
631
632 for (VehicleType type = VehicleType::Begin; type != VehicleType::CompanyEnd; type++) {
633 const auto &mapping = _engine_mngr.mappings[type];
634
635 /* Verify that the engine override manager has at least been set up with the default engines. */
636 assert(std::size(mapping) >= GetOriginalEngineCount(type));
637
638 for (const EngineIDMapping &eid : mapping) {
639 Engine::CreateAtIndex(eid.engine, type, eid.internal_id);
640 }
641 }
642}
643
644void ShowEnginePreviewWindow(EngineID engine);
645
651static bool IsWagon(EngineID index)
652{
653 const Engine *e = Engine::Get(index);
654 return e->type == VehicleType::Train && e->VehInfo<RailVehicleInfo>().railveh_type == RailVehicleType::Wagon;
655}
656
662static void ClearLastVariant(EngineID engine_id, VehicleType type)
663{
664 for (Engine *e : Engine::IterateType(type)) {
665 if (e->display_last_variant == engine_id) e->display_last_variant = EngineID::Invalid();
666 }
667}
668
674void CalcEngineReliability(Engine *e, bool new_month)
675{
676 /* Get source engine for reliability age. This is normally our engine unless variant reliability syncing is requested. */
677 Engine *re = e;
678 while (re->info.variant_id != EngineID::Invalid() && re->info.extra_flags.Test(ExtraEngineFlag::SyncReliability)) {
679 re = Engine::Get(re->info.variant_id);
680 }
681
682 uint32_t age = re->age;
683 if (new_month && re->index > e->index && age != INT32_MAX) age++; /* parent variant's age has not yet updated. */
684
685 /* Check for early retirement */
686 if (e->company_avail.Any() && !_settings_game.vehicle.never_expire_vehicles && e->info.base_life != 0xFF) {
687 int retire_early = e->info.retire_early;
688 uint retire_early_max_age = std::max(0, e->duration_phase_1 + e->duration_phase_2 - retire_early * 12);
689 if (retire_early != 0 && age >= retire_early_max_age) {
690 /* Early retirement is enabled and we're past the date... */
692 ClearLastVariant(e->index, e->type);
694 }
695 }
696
697 if (age < e->duration_phase_1) {
698 uint start = e->reliability_start;
699 e->reliability = age * (e->reliability_max - start) / e->duration_phase_1 + start;
700 } else if ((age -= e->duration_phase_1) < e->duration_phase_2 || _settings_game.vehicle.never_expire_vehicles || e->info.base_life == 0xFF) {
701 /* We are at the peak of this engines life. It will have max reliability.
702 * This is also true if the engines never expire. They will not go bad over time */
704 } else if ((age -= e->duration_phase_2) < e->duration_phase_3) {
705 uint max = e->reliability_max;
706 e->reliability = (int)age * (int)(e->reliability_final - max) / e->duration_phase_3 + max;
707 } else {
708 /* time's up for this engine.
709 * We will now completely retire this design */
712 /* Kick this engine out of the lists */
713 ClearLastVariant(e->index, e->type);
715 }
716
717}
718
721{
722 /* Determine last engine aging year, default to 2050 as previously. */
724
725 for (const Engine *e : Engine::Iterate()) {
726 const EngineInfo *ei = &e->info;
727
728 /* Exclude certain engines */
729 if (!ei->climates.Test(_settings_game.game_creation.landscape)) continue;
730 if (e->type == VehicleType::Train && e->VehInfo<RailVehicleInfo>().railveh_type == RailVehicleType::Wagon) continue;
731
732 /* Base year ending date on half the model life */
733 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(ei->base_intro + (ei->lifelength.base() * CalendarTime::DAYS_IN_LEAP_YEAR) / 2);
734
736 }
737}
738
745void StartupOneEngine(Engine *e, const TimerGameCalendar::YearMonthDay &aging_ymd, uint32_t seed)
746{
747 const EngineInfo *ei = &e->info;
748
749 e->age = 0;
750 e->flags = {};
753
754 /* Vehicles with the same base_intro date shall be introduced at the same time.
755 * Make sure they use the same randomisation of the date. */
756 SavedRandomSeeds saved_seeds;
757 SaveRandomSeeds(&saved_seeds);
758 SetRandomSeed(_settings_game.game_creation.generation_seed ^ seed ^
759 ei->base_intro.base() ^
760 to_underlying(e->type) ^
761 e->GetGRFID());
762 uint32_t r = Random();
763
764 /* Don't randomise the start-date in the first two years after gamestart to ensure availability
765 * of engines in early starting games.
766 * Note: TTDP uses fixed 1922 */
767 e->intro_date = ei->base_intro <= TimerGameCalendar::ConvertYMDToDate(_settings_game.game_creation.starting_year + 2, 0, 1) ? ei->base_intro : (TimerGameCalendar::Date)GB(r, 0, 9) + ei->base_intro;
769 TimerGameCalendar::YearMonthDay intro_ymd = TimerGameCalendar::ConvertDateToYMD(e->intro_date);
770 int aging_months = aging_ymd.year.base() * 12 + aging_ymd.month;
771 int intro_months = intro_ymd.year.base() * 12 + intro_ymd.month;
772 if (intro_ymd.day > 1) intro_months++; // Engines are introduced at the first month start at/after intro date.
773 e->age = aging_months - intro_months;
774 e->company_avail.Set();
776 }
777
778 /* Get parent variant index for syncing reliability via random seed. */
779 const Engine *re = e;
780 while (re->info.variant_id != EngineID::Invalid() && re->info.extra_flags.Test(ExtraEngineFlag::SyncReliability)) {
781 re = Engine::Get(re->info.variant_id);
782 }
783
784 SetRandomSeed(_settings_game.game_creation.generation_seed ^ seed ^
785 (re->index.base() << 16) ^ (re->info.base_intro.base() << 12) ^ (re->info.decay_speed << 8) ^
786 (re->info.lifelength.base() << 4) ^ re->info.retire_early ^
787 to_underlying(e->type) ^
788 e->GetGRFID());
789
790 /* Base reliability defined as a percentage of UINT16_MAX. */
791 const uint16_t RELIABILITY_START = UINT16_MAX * 48 / 100;
792 const uint16_t RELIABILITY_MAX = UINT16_MAX * 75 / 100;
793 const uint16_t RELIABILITY_FINAL = UINT16_MAX * 25 / 100;
794
795 static_assert(RELIABILITY_START == 0x7AE0);
796 static_assert(RELIABILITY_MAX == 0xBFFF);
797 static_assert(RELIABILITY_FINAL == 0x3FFF);
798
799 r = Random();
800 /* 14 bits gives a value between 0 and 16383, which is up to an additional 25%p reliability on top of the base reliability. */
801 e->reliability_start = GB(r, 16, 14) + RELIABILITY_START;
802 e->reliability_max = GB(r, 0, 14) + RELIABILITY_MAX;
803
804 r = Random();
805 e->reliability_final = GB(r, 16, 14) + RELIABILITY_FINAL;
806
807 e->duration_phase_1 = GB(r, 0, 5) + 7;
808 e->duration_phase_2 = std::max(0, int(GB(r, 5, 4)) + ei->base_life.base() * 12 - 96);
809 e->duration_phase_3 = GB(r, 9, 7) + 120;
810
811 RestoreRandomSeeds(saved_seeds);
812
813 e->reliability_spd_dec = ei->decay_speed << 2;
814
815 /* prevent certain engines from ever appearing. */
816 if (!ei->climates.Test(_settings_game.game_creation.landscape)) {
819 }
820}
821
827{
828 /* Aging of vehicles stops, so account for that when starting late */
830 TimerGameCalendar::YearMonthDay aging_ymd = TimerGameCalendar::ConvertDateToYMD(aging_date);
831 uint32_t seed = Random();
832
833 for (Engine *e : Engine::Iterate()) {
834 StartupOneEngine(e, aging_ymd, seed);
835 }
836 for (Engine *e : Engine::Iterate()) {
837 CalcEngineReliability(e, false);
838 }
839
840 /* Update the bitmasks for the vehicle lists */
841 for (Company *c : Company::Iterate()) {
842 c->avail_railtypes = GetCompanyRailTypes(c->index);
843 c->avail_roadtypes = GetCompanyRoadTypes(c->index);
844 }
845
846 /* Invalidate any open purchase lists */
848
851}
852
858static void EnableEngineForCompany(EngineID eid, CompanyID company)
859{
860 Engine *e = Engine::Get(eid);
861 Company *c = Company::Get(company);
862
863 e->company_avail.Set(company);
864 if (e->type == VehicleType::Train) {
866 } else if (e->type == VehicleType::Road) {
868 }
869
870 if (company == _local_company) {
872
873 /* Update the toolbar. */
878 }
879}
880
886static void DisableEngineForCompany(EngineID eid, CompanyID company)
887{
888 Engine *e = Engine::Get(eid);
889 Company *c = Company::Get(company);
890
891 e->company_avail.Reset(company);
892 if (e->type == VehicleType::Train) {
894 } else if (e->type == VehicleType::Road) {
896 }
897
898 if (company == _local_company) {
899 ClearLastVariant(e->index, e->type);
901 }
902}
903
910static void AcceptEnginePreview(EngineID eid, CompanyID company, int recursion_depth = 0)
911{
912 Engine *e = Engine::Get(eid);
913
914 e->preview_company = CompanyID::Invalid();
915 e->preview_asked.Set();
916
917 EnableEngineForCompany(eid, company);
918
919 /* Notify preview window to remove this engine.
920 * Note: We cannot directly close the window.
921 * In singleplayer this function is called from the preview window, so
922 * we have to use the GUI-scope scheduling of InvalidateWindowData.
923 */
925
926 /* Don't search for variants to include if we are 10 levels deep already. */
927 if (recursion_depth >= 10) return;
928
929 /* Find variants to be included in preview. */
930 for (Engine *ve : Engine::IterateType(e->type)) {
931 if (ve->index != eid && ve->info.variant_id == eid && ve->info.extra_flags.Test(ExtraEngineFlag::JoinPreview)) {
932 AcceptEnginePreview(ve->index, company, recursion_depth + 1);
933 }
934 }
935}
936
942static CompanyID GetPreviewCompany(Engine *e)
943{
944 CompanyID best_company = CompanyID::Invalid();
945
946 /* For trains the cargomask has no useful meaning, since you can attach other wagons */
947 CargoTypes cargomask = e->type != VehicleType::Train ? GetUnionOfArticulatedRefitMasks(e->index, true) : ALL_CARGOTYPES;
948
949 int32_t best_hist = -1;
950 for (const Company *c : Company::Iterate()) {
951 if (c->block_preview == 0 && !e->preview_asked.Test(c->index) &&
952 c->old_economy[0].performance_history > best_hist) {
953
954 /* Check whether the company uses similar vehicles */
955 for (const Vehicle *v : Vehicle::Iterate()) {
956 if (v->owner != c->index || v->type != e->type) continue;
957 if (!v->GetEngine()->CanCarryCargo() || !cargomask.Test(v->cargo_type)) continue;
958
959 best_hist = c->old_economy[0].performance_history;
960 best_company = c->index;
961 break;
962 }
963 }
964 }
965
966 return best_company;
967}
968
976static bool IsVehicleTypeDisabled(VehicleType type, bool ai)
977{
978 switch (type) {
979 case VehicleType::Train: return _settings_game.vehicle.max_trains == 0 || (ai && _settings_game.ai.ai_disable_veh_train);
980 case VehicleType::Road: return _settings_game.vehicle.max_roadveh == 0 || (ai && _settings_game.ai.ai_disable_veh_roadveh);
981 case VehicleType::Ship: return _settings_game.vehicle.max_ships == 0 || (ai && _settings_game.ai.ai_disable_veh_ship);
982 case VehicleType::Aircraft: return _settings_game.vehicle.max_aircraft == 0 || (ai && _settings_game.ai.ai_disable_veh_aircraft);
983
984 default: NOT_REACHED();
985 }
986}
987
989static const IntervalTimer<TimerGameCalendar> _calendar_engines_daily({TimerGameCalendar::Trigger::Day, TimerGameCalendar::Priority::Engine}, [](auto)
990{
991 for (Company *c : Company::Iterate()) {
992 c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes, TimerGameCalendar::date);
993 c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes, TimerGameCalendar::date);
994 }
995
997
998 for (Engine *e : Engine::Iterate()) {
999 EngineID i = e->index;
1000 if (e->flags.Test(EngineFlag::ExclusivePreview)) {
1001 if (e->preview_company != CompanyID::Invalid()) {
1002 if (!--e->preview_wait) {
1004 e->preview_company = CompanyID::Invalid();
1005 }
1006 } else if (e->preview_asked.Count() < MAX_COMPANIES) {
1007 e->preview_company = GetPreviewCompany(e);
1008
1009 if (e->preview_company == CompanyID::Invalid()) {
1010 e->preview_asked.Set();
1011 continue;
1012 }
1013
1014 e->preview_asked.Set(e->preview_company);
1015 e->preview_wait = 20;
1016 /* AIs are intentionally not skipped for preview even if they cannot build a certain
1017 * vehicle type. This is done to not give poor performing human companies an "unfair"
1018 * boost that they wouldn't have gotten against other human companies. The check on
1019 * the line below is just to make AIs not notice that they have a preview if they
1020 * cannot build the vehicle. */
1021 if (!IsVehicleTypeDisabled(e->type, true)) AI::NewEvent(e->preview_company, new ScriptEventEnginePreview(i));
1022 if (IsInteractiveCompany(e->preview_company)) ShowEnginePreviewWindow(i);
1023 }
1024 }
1025 }
1026});
1027
1033{
1034 for (Engine *e : Engine::Iterate()) {
1035 e->company_hidden.Reset(cid);
1036 }
1037}
1038
1046CommandCost CmdSetVehicleVisibility(DoCommandFlags flags, EngineID engine_id, bool hide)
1047{
1048 Engine *e = Engine::GetIfValid(engine_id);
1049 if (e == nullptr || _current_company >= MAX_COMPANIES) return CMD_ERROR;
1050 if (!IsEngineBuildable(e->index, e->type, _current_company)) return CMD_ERROR;
1051
1052 if (flags.Test(DoCommandFlag::Execute)) {
1055 }
1056
1057 return CommandCost();
1058}
1059
1067CommandCost CmdWantEnginePreview(DoCommandFlags flags, EngineID engine_id)
1068{
1069 Engine *e = Engine::GetIfValid(engine_id);
1070 if (e == nullptr || !e->flags.Test(EngineFlag::ExclusivePreview) || e->preview_company != _current_company) return CMD_ERROR;
1071
1073
1074 return CommandCost();
1075}
1076
1085CommandCost CmdEngineCtrl(DoCommandFlags flags, EngineID engine_id, CompanyID company_id, bool allow)
1086{
1087 if (_current_company != OWNER_DEITY) return CMD_ERROR;
1088
1089 if (!Engine::IsValidID(engine_id) || !Company::IsValidID(company_id)) return CMD_ERROR;
1090
1091 if (flags.Test(DoCommandFlag::Execute)) {
1092 if (allow) {
1093 EnableEngineForCompany(engine_id, company_id);
1094 } else {
1095 DisableEngineForCompany(engine_id, company_id);
1096 }
1097 }
1098
1099 return CommandCost();
1100}
1101
1108{
1109 EngineID index = e->index;
1110
1111 /* In case the company didn't build the vehicle during the intro period,
1112 * prevent that company from getting future intro periods for a while. */
1114 for (Company *c : Company::Iterate()) {
1115 if (!e->company_avail.Test(c->index)) continue;
1116
1117 /* Check the company's 'ALL_GROUP' group statistics. This only includes countable vehicles, which is fine
1118 * as those are the only engines that can be given exclusive previews. */
1119 if (GetGroupNumEngines(c->index, ALL_GROUP, e->index) == 0) {
1120 /* The company did not build this engine during preview. */
1121 c->block_preview = 20;
1122 }
1123 }
1124 }
1125
1128
1129 /* Now available for all companies */
1130 e->company_avail.Set();
1131
1132 /* Do not introduce new rail wagons */
1133 if (IsWagon(index)) return;
1134
1135 if (e->type == VehicleType::Train) {
1136 /* maybe make another rail type available */
1137 assert(e->VehInfo<RailVehicleInfo>().railtypes != RailTypes{});
1139 for (Company *c : Company::Iterate()) c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | introduced, TimerGameCalendar::date);
1140 } else if (e->type == VehicleType::Road) {
1141 /* maybe make another road type available */
1142 assert(e->VehInfo<RoadVehicleInfo>().roadtype < ROADTYPE_END);
1143 for (Company *c : Company::Iterate()) c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes | GetRoadTypeInfo(e->VehInfo<RoadVehicleInfo>().roadtype)->introduces_roadtypes, TimerGameCalendar::date);
1144 }
1145
1146 /* Only broadcast event if AIs are able to build this vehicle type. */
1147 if (!IsVehicleTypeDisabled(e->type, true)) AI::BroadcastNewEvent(new ScriptEventEngineAvailable(index));
1148
1149 /* Only provide the "New Vehicle available" news paper entry, if engine can be built. */
1150 if (!IsVehicleTypeDisabled(e->type, false) && !e->info.extra_flags.Test(ExtraEngineFlag::NoNews)) {
1151 AddNewsItem(GetEncodedString(STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE,
1152 GetEngineCategoryName(index),
1155 }
1156
1157 /* Update the toolbar. */
1161
1162 /* Remove from preview windows */
1164}
1165
1168{
1170 bool refresh = false;
1171 for (Engine *e : Engine::Iterate()) {
1172 /* Age the vehicle */
1173 if (e->flags.Test(EngineFlag::Available) && e->age != INT32_MAX) {
1174 e->age++;
1175 CalcEngineReliability(e, true);
1176 refresh = true;
1177 }
1178
1179 /* Do not introduce invalid engines */
1180 if (!e->IsEnabled()) continue;
1181
1182 if (!e->flags.Test(EngineFlag::Available) && TimerGameCalendar::date >= (e->intro_date + CalendarTime::DAYS_IN_YEAR)) {
1183 /* Introduce it to all companies */
1185 } else if (!e->flags.Any({EngineFlag::Available, EngineFlag::ExclusivePreview}) && TimerGameCalendar::date >= e->intro_date) {
1186 /* Introduction date has passed...
1187 * Check if it is allowed to build this vehicle type at all
1188 * based on the current game settings. If not, it does not
1189 * make sense to show the preview dialog to any company. */
1190 if (IsVehicleTypeDisabled(e->type, false)) continue;
1191
1192 /* Do not introduce new rail wagons */
1193 if (IsWagon(e->index)) continue;
1194
1195 /* Engine has no preview */
1196 if (e->info.extra_flags.Test(ExtraEngineFlag::NoPreview)) continue;
1197
1198 /* Show preview dialog to one of the companies. */
1199 e->flags.Set(EngineFlag::ExclusivePreview);
1200 e->preview_company = CompanyID::Invalid();
1201 e->preview_asked = CompanyMask{};
1202 }
1203 }
1204
1205 InvalidateWindowClassesData(WC_BUILD_VEHICLE); // rebuild the purchase list (esp. when sorted by reliability)
1206
1207 if (refresh) {
1210 }
1211 }
1212}
1213
1214static const IntervalTimer<TimerGameCalendar> _calendar_engines_monthly({TimerGameCalendar::Trigger::Month, TimerGameCalendar::Priority::Engine}, [](auto)
1215{
1217});
1218
1224static bool IsUniqueEngineName(const std::string &name)
1225{
1226 for (const Engine *e : Engine::Iterate()) {
1227 if (!e->name.empty() && e->name == name) return false;
1228 }
1229
1230 return true;
1231}
1232
1240CommandCost CmdRenameEngine(DoCommandFlags flags, EngineID engine_id, const std::string &text)
1241{
1242 Engine *e = Engine::GetIfValid(engine_id);
1243 if (e == nullptr) return CMD_ERROR;
1244
1245 bool reset = text.empty();
1246
1247 if (!reset) {
1249 if (!IsUniqueEngineName(text)) return CommandCost(STR_ERROR_NAME_MUST_BE_UNIQUE);
1250 }
1251
1252 if (flags.Test(DoCommandFlag::Execute)) {
1253 if (reset) {
1254 e->name.clear();
1255 } else {
1256 e->name = text;
1257 }
1258
1260 }
1261
1262 return CommandCost();
1263}
1264
1265
1274bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company)
1275{
1276 const Engine *e = Engine::GetIfValid(engine);
1277
1278 /* check if it's an engine that is in the engine array */
1279 if (e == nullptr) return false;
1280
1281 /* check if it's an engine of specified type */
1282 if (e->type != type) return false;
1283
1284 /* check if it's available ... */
1285 if (company == OWNER_DEITY) {
1286 /* ... for any company (preview does not count) */
1287 if (!e->flags.Test(EngineFlag::Available) || e->company_avail.None()) return false;
1288 } else {
1289 /* ... for this company */
1290 if (!e->company_avail.Test(company)) return false;
1291 }
1292
1293 if (!e->IsEnabled()) return false;
1294
1295 if (type == VehicleType::Train && company != OWNER_DEITY) {
1296 /* Check if the rail type is available to this company */
1297 const Company *c = Company::Get(company);
1298 if (!GetAllCompatibleRailTypes(e->VehInfo<RailVehicleInfo>().railtypes).Any(c->avail_railtypes)) return false;
1299 }
1300 if (type == VehicleType::Road && company != OWNER_DEITY) {
1301 /* Check if the road type is available to this company */
1302 const Company *c = Company::Get(company);
1303 if (!GetRoadTypeInfo(e->VehInfo<RoadVehicleInfo>().roadtype)->powered_roadtypes.Any(c->avail_roadtypes)) return false;
1304 }
1305
1306 return true;
1307}
1308
1316{
1317 const Engine *e = Engine::GetIfValid(engine);
1318
1319 /* check if it's an engine that is in the engine array */
1320 if (e == nullptr) return false;
1321
1322 if (!e->CanCarryCargo()) return false;
1323
1324 const EngineInfo *ei = &e->info;
1325 if (ei->refit_mask.None()) return false;
1326
1327 /* Are there suffixes?
1328 * Note: This does not mean the suffixes are actually available for every consist at any time. */
1330
1331 /* Is there any cargo except the default cargo? */
1332 CargoType default_cargo = e->GetDefaultCargoType();
1333 return IsValidCargoType(default_cargo) && ei->refit_mask != default_cargo;
1334}
1335
1340{
1341 TimerGameCalendar::Date min_date{INT32_MAX};
1342
1343 for (const Engine *e : Engine::Iterate()) {
1344 if (!e->IsEnabled()) continue;
1345
1346 /* Don't consider train wagons, we need a powered engine available. */
1347 if (e->type == VehicleType::Train && e->VehInfo<RailVehicleInfo>().railveh_type == RailVehicleType::Wagon) continue;
1348
1349 /* We have an available engine... yay! */
1350 if (e->flags.Test(EngineFlag::Available) && e->company_avail.Any()) return;
1351
1352 /* Okay, try to find the earliest date. */
1353 min_date = std::min(min_date, e->info.base_intro);
1354 }
1355
1356 if (min_date < INT32_MAX) {
1357 ShowErrorMessage(GetEncodedString(STR_ERROR_NO_VEHICLES_AVAILABLE_YET),
1358 GetEncodedString(STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION, min_date), WL_WARNING);
1359 } else {
1360 ShowErrorMessage(GetEncodedString(STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL),
1361 GetEncodedString(STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION), WL_WARNING);
1362 }
1363}
Base functions for all AIs.
Base for aircraft.
CargoTypes GetUnionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type)
Ors the refit_masks of all articulated parts.
Functions related to articulated vehicles.
void AddRemoveEngineFromAutoreplaceAndBuildWindows(VehicleType type)
When an engine is made buildable or is removed from being buildable, add/remove it from the build/aut...
Functions related to the autoreplace GUIs.
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
static constexpr CargoLabel CT_INVALID
Invalid cargo type.
Definition cargo_type.h:72
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:110
static constexpr CargoLabel CT_PASSENGERS
Available types of cargo Labels may be re-used between different climates.
Definition cargo_type.h:31
CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:22
@ Passengers
Passengers.
Definition cargotype.h:51
bool IsCargoInClass(CargoType cargo, CargoClasses cc)
Does cargo c have cargo class cc?
Definition cargotype.h:236
static void BroadcastNewEvent(ScriptEvent *event, CompanyID skip_company=CompanyID::Invalid())
Broadcast a new event to all active AIs.
Definition ai_core.cpp:240
static void NewEvent(CompanyID company, ScriptEvent *event)
Queue a new event for an AI.
Definition ai_core.cpp:221
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr bool None() const
Test if none of the values are set.
constexpr Timpl & Reset()
Reset all bits.
constexpr Timpl & Set()
Set all bits.
constexpr bool Any(const Timpl &other) const
Test if any of the given values are set.
Common return value for all commands.
StringID GetAircraftTypeText() const
Get the name of the aircraft type for display purposes.
Definition engine.cpp:493
uint GetPower() const
Returns the power of the engine for display and sorting purposes.
Definition engine.cpp:415
const Engine * GetDisplayVariant() const
Get the last display variant for an engine.
uint16_t GetRange() const
Get the range of an aircraft type.
Definition engine.cpp:478
uint32_t GetGRFID() const
Retrieve the GRF ID of the NewGRF the engine is tied to.
Definition engine.cpp:182
uint16_t reliability_spd_dec
Speed of reliability decay between services (per day).
Definition engine_base.h:50
Money GetCost() const
Return how much a new engine costs.
Definition engine.cpp:343
uint16_t reliability_start
Initial reliability of the engine.
Definition engine_base.h:51
TimerGameCalendar::Date intro_date
Date of introduction of the engine.
Definition engine_base.h:46
const GRFFile * GetGRF() const
Retrieve the NewGRF the engine is tied to.
static Pool::IterateWrapperFiltered< Engine, EngineTypeFilter > IterateType(VehicleType vt, size_t from=0)
Returns an iterable ensemble of all valid engines of the given type.
uint GetDisplayMaxSpeed() const
Returns max speed of the engine for display purposes.
Definition engine.cpp:383
uint DetermineCapacity(const Vehicle *v, uint16_t *mail_capacity=nullptr) const
Determines capacity of a given vehicle from scratch.
Definition engine.cpp:226
EngineFlags flags
Flags of the engine.
Definition engine_base.h:57
CompanyMask company_avail
Bit for each company whether the engine is available for that company.
Definition engine_base.h:40
uint16_t reliability_max
Maximal reliability of the engine.
Definition engine_base.h:52
uint GetDisplayWeight() const
Returns the weight of the engine for display purposes.
Definition engine.cpp:433
bool IsEnabled() const
Checks whether the engine is a valid (non-articulated part of an) engine.
Definition engine.cpp:172
VehicleType type
Vehicle type, ie VehicleType::Road, VehicleType::Train, etc.
Definition engine_base.h:62
bool IsVariantHidden(CompanyID c) const
Check whether the engine variant chain is hidden in the GUI for the given company.
Definition engine.cpp:513
uint16_t reliability_final
Final reliability of the engine.
Definition engine_base.h:53
CompanyID preview_company
Company which is currently being offered a preview CompanyID::Invalid() means no company.
Definition engine_base.h:59
TimerGameCalendar::Date GetLifeLengthInDays() const
Returns the vehicle's (not model's!) life length in days.
Definition engine.cpp:468
uint16_t duration_phase_3
Third reliability phase in months, decaying to reliability_final.
Definition engine_base.h:56
uint16_t duration_phase_2
Second reliability phase in months, keeping reliability_max.
Definition engine_base.h:55
CargoType GetDefaultCargoType() const
Determines the default cargo type of an engine.
Definition engine_base.h:94
CompanyMask company_hidden
Bit for each company whether the engine is normally hidden in the build gui for that company.
Definition engine_base.h:41
Money GetRunningCost() const
Return how much the running costs of this engine are.
Definition engine.cpp:306
uint16_t reliability
Current reliability of the engine.
Definition engine_base.h:49
CompanyMask preview_asked
Bit for each company which has already been offered a preview.
Definition engine_base.h:42
uint GetDisplayMaxTractiveEffort() const
Returns the tractive effort of the engine for display purposes.
Definition engine.cpp:451
int32_t age
Age of the engine in months.
Definition engine_base.h:47
bool IsHidden(CompanyID c) const
Check whether the engine is hidden in the GUI for the given company.
bool CanCarryCargo() const
Determines whether an engine can carry something.
Definition engine.cpp:193
std::string name
Custom name of engine.
Definition engine_base.h:44
uint16_t duration_phase_1
First reliability phase in months, increasing reliability from reliability_start to reliability_max.
Definition engine_base.h:54
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
RoadTypes powered_roadtypes
bitmask to the OTHER roadtypes on which a vehicle of THIS roadtype generates power
Definition road.h:96
static constexpr TimerGameTick::Ticks CARGO_AGING_TICKS
Cycle duration for aging cargo.
static Date ConvertYMDToDate(Year year, Month month, Day day)
Converts a tuple of Year, Month and Day to a Date.
static YearMonthDay ConvertDateToYMD(Date date)
Converts a Date to a Year, Month & Day.
static Date date
Current date in days (day counter).
static Year year
Current year, starting at 0.
StrongType::Typedef< int32_t, struct YearTag< struct Calendar >, StrongType::Compare, StrongType::Integer > Year
StrongType::Typedef< int32_t, DateTag< struct Calendar >, StrongType::Compare, StrongType::Integer > Date
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ Execute
execute the given command
Definition of stuff that is very close to a company, like the company struct itself.
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.
Functions related to companies.
bool IsInteractiveCompany(CompanyID company)
Is the user representing company?
static constexpr Owner OWNER_DEITY
The object is owned by a superuser / goal script.
Some simple functions to help with accessing containers.
auto Slide(TIter first, TIter last, TIter position) -> std::pair< TIter, TIter >
Move elements between first and last to a new position, rotating elements in between as necessary.
Money GetPrice(Price index, uint cost_factor, const GRFFile *grf_file, int shift)
Determine a certain price.
Definition economy.cpp:938
Price
Enumeration of all base prices for use with Prices.
@ BuildVehicleWagon
Price for purchasing new wagons.
@ BuildVehicleTrain
Price for purchasing new train engines.
@ BuildVehicleShip
Price for purchasing new ships.
@ Invalid
Invalid base price.
@ BuildVehicleAircraft
Price for purchasing new aircrafts.
@ RunningAircraft
Running cost of aircrafts.
@ BuildVehicleRoad
Price for purchasing new road vehicles.
@ RunningShip
Running cost of ships.
void ClearEnginesHiddenFlagOfCompany(CompanyID cid)
Clear the 'hidden' flag for all engines of a new company.
Definition engine.cpp:1032
void SetYearEngineAgingStops()
Compute the value for _year_engine_aging_stops.
Definition engine.cpp:720
static void NewVehicleAvailable(Engine *e)
An engine has become available for general use.
Definition engine.cpp:1107
void SetupEngines()
Initialise the engine pool with the data from the original vehicles.
Definition engine.cpp:627
static CompanyID GetPreviewCompany(Engine *e)
Get the best company for an engine preview.
Definition engine.cpp:942
static void ClearLastVariant(EngineID engine_id, VehicleType type)
Ensure engine is not set as the last used variant for any other engine.
Definition engine.cpp:662
uint8_t GetOriginalEngineOffset(VehicleType type)
Get the index offset for original engines of a VehicleType.
Definition engine.cpp:77
static bool IsVehicleTypeDisabled(VehicleType type, bool ai)
Checks if a vehicle type is disabled for all/ai companies.
Definition engine.cpp:976
static const IntervalTimer< TimerGameCalendar > _calendar_engines_daily({TimerGameCalendar::Trigger::Day, TimerGameCalendar::Priority::Engine}, [](auto) { for(Company *c :Company::Iterate()) { c->avail_railtypes=AddDateIntroducedRailTypes(c->avail_railtypes, TimerGameCalendar::date);c->avail_roadtypes=AddDateIntroducedRoadTypes(c->avail_roadtypes, TimerGameCalendar::date);} if(TimerGameCalendar::year >=_year_engine_aging_stops) return;for(Engine *e :Engine::Iterate()) { EngineID i=e->index;if(e->flags.Test(EngineFlag::ExclusivePreview)) { if(e->preview_company !=CompanyID::Invalid()) { if(!--e->preview_wait) { InvalidateWindowClassesData(WC_ENGINE_PREVIEW);e->preview_company=CompanyID::Invalid();} } else if(e->preview_asked.Count()< MAX_COMPANIES) { e->preview_company=GetPreviewCompany(e);if(e->preview_company==CompanyID::Invalid()) { e->preview_asked.Set();continue;} e->preview_asked.Set(e->preview_company);e->preview_wait=20;if(!IsVehicleTypeDisabled(e->type, true)) AI::NewEvent(e->preview_company, new ScriptEventEnginePreview(i));if(IsInteractiveCompany(e->preview_company)) ShowEnginePreviewWindow(i);} } } })
Daily check to offer an exclusive engine preview to the companies.
static void AcceptEnginePreview(EngineID eid, CompanyID company, int recursion_depth=0)
Company company accepts engine eid for preview.
Definition engine.cpp:910
CommandCost CmdRenameEngine(DoCommandFlags flags, EngineID engine_id, const std::string &text)
Rename an engine.
Definition engine.cpp:1240
CommandCost CmdWantEnginePreview(DoCommandFlags flags, EngineID engine_id)
Accept an engine prototype.
Definition engine.cpp:1067
void CalendarEnginesMonthlyLoop()
Monthly update of the availability, reliability, and preview offers of the engines.
Definition engine.cpp:1167
static bool IsUniqueEngineName(const std::string &name)
Is name still free as name for an engine?
Definition engine.cpp:1224
bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company)
Check if an engine is buildable.
Definition engine.cpp:1274
uint8_t GetOriginalEngineCount(VehicleType type)
Get the number of original engines for a VehicleType.
Definition engine.cpp:58
static TimerGameCalendar::Year _year_engine_aging_stops
Year that engine aging stops.
Definition engine.cpp:51
static void DisableEngineForCompany(EngineID eid, CompanyID company)
Forbids engine eid to be used by a company company.
Definition engine.cpp:886
void StartupEngines()
Start/initialise all our engines.
Definition engine.cpp:826
static bool IsWagon(EngineID index)
Determine whether an engine type is a wagon (and not a loco).
Definition engine.cpp:651
CommandCost CmdEngineCtrl(DoCommandFlags flags, EngineID engine_id, CompanyID company_id, bool allow)
Allow or forbid a specific company to use an engine.
Definition engine.cpp:1085
void StartupOneEngine(Engine *e, const TimerGameCalendar::YearMonthDay &aging_ymd, uint32_t seed)
Start/initialise one engine.
Definition engine.cpp:745
void CheckEngines()
Check for engines that have an appropriate availability.
Definition engine.cpp:1339
bool IsEngineRefittable(EngineID engine)
Check if an engine is refittable.
Definition engine.cpp:1315
CommandCost CmdSetVehicleVisibility(DoCommandFlags flags, EngineID engine_id, bool hide)
Set the visibility of an engine.
Definition engine.cpp:1046
void CalcEngineReliability(Engine *e, bool new_month)
Update Engine::reliability and (if needed) update the engine GUIs.
Definition engine.cpp:674
static void EnableEngineForCompany(EngineID eid, CompanyID company)
Allows engine eid to be used by a company company.
Definition engine.cpp:858
Base class for engines.
Functions related to engines.
StringID GetEngineCategoryName(EngineID engine)
Return the category of an engine.
Engine GUI functions, used by build_vehicle_gui and autoreplace_gui.
@ AIR_CTOL
Conventional Take Off and Landing, i.e. planes.
@ SyncReliability
Engine reliability will be synced with variant parent.
@ NoNews
No 'new vehicle' news will be generated.
@ JoinPreview
Engine will join exclusive preview with variant parent.
@ NoPreview
No exclusive preview will be offered.
@ NoDefaultCargoMultiplier
Use the new capacity algorithm. The default cargotype of the vehicle does not affect capacity multipl...
static const uint MAX_LENGTH_ENGINE_NAME_CHARS
The maximum length of an engine name in characters including '\0'.
PoolID< uint16_t, struct EngineIDTag, 64000, 0xFFFF > EngineID
Unique identification number of an engine.
Definition engine_type.h:26
uint64_t PackEngineNameDParam(EngineID engine_id, EngineNameContext context, uint32_t extra_data=0)
Combine an engine ID and a name context to an engine name StringParameter.
@ Available
This vehicle is available to everyone.
@ ExclusivePreview
This vehicle is in the exclusive preview stage, either being used or being offered to a company.
@ PreviewNews
Name is shown in exclusive preview or newspaper.
@ Multihead
indicates a combination of two locomotives
Definition engine_type.h:33
@ Wagon
simple wagon, not motorized
Definition engine_type.h:34
This file contains all the data for vehicles.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
Definition enum_type.hpp:21
Functions related to errors.
@ WL_WARNING
Other information.
Definition error.h:25
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, CommandCost &cc)
Display an error message in a window.
uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e)
Get the number of engines with EngineID id_e in the group with GroupID id_g and its sub-groups.
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1554
static constexpr GroupID ALL_GROUP
All vehicles are in this group.
Definition group_type.h:17
Base for the NewGRF implementation.
void ReloadNewGRFData()
Reload all NewGRF files during a running game.
@ RefitCapacity
Cargo capacity after refit.
@ CargoSuffix
Show suffix after cargo name.
@ CBID_VEHICLE_REFIT_CAPACITY
Refit capacity, the passed vehicle needs to have its ->cargo_type set to the cargo we are refitting t...
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
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.
Functions for NewGRF engines.
@ PROP_AIRCRAFT_PASSENGER_CAPACITY
Passenger Capacity.
@ PROP_ROADVEH_WEIGHT
Weight in 1/4 t.
@ PROP_TRAIN_COST_FACTOR
Purchase cost (if dualheaded: sum of both vehicles).
@ PROP_TRAIN_WEIGHT
Weight in t (if dualheaded: for each single vehicle).
@ PROP_AIRCRAFT_RANGE
Aircraft range.
@ PROP_TRAIN_CARGO_CAPACITY
Capacity (if dualheaded: for each single vehicle).
@ PROP_AIRCRAFT_RUNNING_COST_FACTOR
Yearly runningcost.
@ PROP_ROADVEH_RUNNING_COST_FACTOR
Yearly runningcost.
@ PROP_TRAIN_TRACTIVE_EFFORT
Tractive effort coefficient in 1/256.
@ PROP_SHIP_CARGO_CAPACITY
Capacity.
@ PROP_ROADVEH_TRACTIVE_EFFORT
Tractive effort coefficient in 1/256.
@ PROP_SHIP_COST_FACTOR
Purchase cost.
@ PROP_ROADVEH_CARGO_CAPACITY
Capacity.
@ PROP_AIRCRAFT_SPEED
Max. speed: 1 unit = 8 mph = 12.8 km-ish/h.
@ PROP_AIRCRAFT_MAIL_CAPACITY
Mail Capacity.
@ PROP_SHIP_SPEED
Max. speed: 1 unit = 1/3.2 mph = 0.5 km-ish/h.
@ PROP_SHIP_RUNNING_COST_FACTOR
Yearly runningcost.
@ PROP_ROADVEH_COST_FACTOR
Purchase cost.
@ PROP_ROADVEH_POWER
Power in 10 HP.
@ PROP_AIRCRAFT_COST_FACTOR
Purchase cost.
@ PROP_TRAIN_RUNNING_COST_FACTOR
Yearly runningcost (if dualheaded: sum of both vehicles).
@ PROP_TRAIN_POWER
Power in hp (if dualheaded: sum of both vehicles).
@ PROP_TRAIN_SPEED
Max. speed: 1 unit = 1/1.6 mph = 1 km-ish/h.
@ PROP_ROADVEH_SPEED
Max. speed: 1 unit = 1/0.8 mph = 2 km-ish/h.
Functions related to news.
void AddNewsItem(EncodedString &&headline, NewsType type, NewsStyle style, NewsFlags flags, NewsReference ref1={}, NewsReference ref2={}, std::unique_ptr< NewsAllocatedData > &&data=nullptr, AdviceType advice_type=AdviceType::Invalid)
Add a new newsitem to be shown.
Definition news_gui.cpp:919
@ NewVehicles
New vehicle has become available.
Definition news_type.h:42
@ Vehicle
Vehicle news item. (new engine available).
Definition news_type.h:81
Some methods of Pool are placed here in order to reduce compilation time and binary size.
#define INSTANTIATE_POOL_METHODS(name)
Force instantiation of pool methods so we don't get linker errors.
RailTypes GetCompanyRailTypes(CompanyID company, bool introduces)
Get the rail types the given company can build.
Definition rail.cpp:137
RailTypes AddDateIntroducedRailTypes(RailTypes current, TimerGameCalendar::Date date)
Add the rail types that are to be introduced at the given date.
Definition rail.cpp:104
RailTypes GetAllIntroducesRailTypes(RailTypes railtypes)
Returns all introduced railtypes for a set of railtypes.
Definition rail.h:337
RailTypes GetAllCompatibleRailTypes(RailTypes railtypes)
Returns all compatible railtypes for a set of railtypes.
Definition rail.h:313
EnumBitSet< RailType, uint64_t > RailTypes
Allow incrementing of Track variables.
Definition rail_type.h:38
void SetRandomSeed(uint32_t seed)
(Re)set the state of the random number generators.
Pseudo random number generator.
void SaveRandomSeeds(SavedRandomSeeds *storage)
Saves the current seeds.
void RestoreRandomSeeds(const SavedRandomSeeds &storage)
Restores previously saved seeds.
RoadTypes GetCompanyRoadTypes(CompanyID company, bool introduces)
Get the road types the given company can build.
Definition road.cpp:210
RoadTypes AddDateIntroducedRoadTypes(RoadTypes current, TimerGameCalendar::Date date)
Add the road types that are to be introduced at the given date.
Definition road.cpp:177
const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition road.h:215
@ ROADTYPE_END
Used for iterations.
Definition road_type.h:27
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
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
size_t Utf8StringLength(std::string_view str)
Get the length of an UTF-8 encoded string in number of characters and thus not the number of bytes th...
Definition string.cpp:351
Functions related to low-level strings.
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:90
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Information about a aircraft vehicle.
uint16_t multiplier
Capacity multiplier for vehicles. (8 fractional bits).
Definition cargotype.h:81
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:139
RoadTypes avail_roadtypes
Road types available to this company.
RailTypes avail_railtypes
Rail types available to this company.
Projection to get a unique key of an EngineIDMapping, used for sorting in EngineOverrideManager.
Information about a vehicle.
TimerGameCalendar::Year base_life
Basic duration of engine availability (without random parts). 0xFF means infinite life.
LandscapeTypes climates
Climates supported by the engine.
EngineID variant_id
Engine variant ID. If set, will be treated specially in purchase lists.
VehicleCallbackMasks callback_mask
Bitmask of vehicle callbacks that have to be called.
TimerGameCalendar::Date base_intro
Basic date of engine introduction (without random parts).
int8_t retire_early
Number of years early to retire vehicle.
TimerGameCalendar::Year lifelength
Lifetime of a single vehicle.
Stores the mapping of EngineID to the internal id of newgrfs.
static bool ResetToCurrentNewGRFConfig()
Tries to reset the engine mapping to match the current NewGRF configuration.
Definition engine.cpp:611
void ResetToDefaultMapping()
Initializes the EngineOverrideManager with the default engines.
Definition engine.cpp:535
EngineID UseUnreservedID(VehicleType type, uint16_t grf_local_id, uint32_t grfid, bool static_access)
Look for an unreserved EngineID matching the local id, and reserve it if found.
Definition engine.cpp:575
EngineID GetID(VehicleType type, uint16_t grf_local_id, uint32_t grfid)
Looks up an EngineID in the EngineOverrideManager.
Definition engine.cpp:556
Dynamic data of a loaded NewGRF.
Definition newgrf.h:118
static Pool::IterateWrapper< Vehicle > Iterate(size_t from=0)
static T * CreateAtIndex(EngineID index, Targs &&... args)
static Engine * Get(auto index)
static bool IsValidID(auto index)
static Engine * GetIfValid(auto index)
Information about a rail vehicle.
Definition engine_type.h:74
RailTypes railtypes
Railtypes, mangled if elrail is disabled.
Definition engine_type.h:78
RailVehicleType railveh_type
Type of rail vehicle.
Definition engine_type.h:76
Information about a road vehicle.
RoadType roadtype
Road type.
Stores the state of all random number generators.
Information about a ship vehicle.
Definition engine_type.h:99
Vehicle data structure.
EngineID engine_type
The type of engine used for this vehicle.
CargoType cargo_type
type of cargo this vehicle is carrying
uint8_t cargo_subtype
Used for livery refits (NewGRF variations).
Definition of Interval and OneShot timers.
Definition of the game-calendar-timer.
Definition of the tick-based game-timer.
@ TRANSPORT_ROAD
Transport by road vehicle.
@ TRANSPORT_WATER
Transport over water.
@ TRANSPORT_AIR
Transport through air.
Functions related to vehicles.
bool IsCompanyBuildableVehicleType(VehicleType type)
Is the given vehicle type buildable by a company?
VehicleType
Available vehicle types.
@ Ship
Ship vehicle type.
@ Begin
Begin marker.
@ Invalid
Non-existing type of vehicle.
@ CompanyEnd
Last company-ownable type.
@ Aircraft
Aircraft vehicle type.
@ Road
Road vehicle type.
@ Train
Train vehicle type.
EnumIndexArray< T, VehicleType, Tend > VehicleTypeIndexArray
Array with VehicleType as index.
static const int GROUND_ACCELERATION
Acceleration due to gravity, 9.8 m/s^2.
void CloseWindowByClass(WindowClass cls, int data)
Close all windows of a given class.
Definition window.cpp:1222
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting).
Definition window.cpp:3230
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:3322
void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope)
Mark window data of all windows of a given class as invalid (in need of re-computing) Note that by de...
Definition window.cpp:3340
Window functions not directly related to making/drawing windows.
@ WC_BUILD_TOOLBAR
Build toolbar; Window numbers:
Definition window_type.h:79
@ WC_REPLACE_VEHICLE
Replace vehicle window; Window numbers:
@ WC_ENGINE_PREVIEW
Engine preview window; Window numbers:
@ WC_MAIN_TOOLBAR
Main toolbar (the long bar at the top); Window numbers:
Definition window_type.h:64
@ WC_BUILD_VEHICLE
Build vehicle; Window numbers: