OpenTTD Source 20251019-master-g9f7f314f81
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 <http://www.gnu.org/licenses/>.
6 */
7
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
54const uint8_t _engine_counts[4] = {
55 lengthof(_orig_rail_vehicle_info),
56 lengthof(_orig_road_vehicle_info),
57 lengthof(_orig_ship_vehicle_info),
58 lengthof(_orig_aircraft_vehicle_info),
59};
60
62const uint8_t _engine_offsets[4] = {
63 0,
64 lengthof(_orig_rail_vehicle_info),
65 lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info),
66 lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info) + lengthof(_orig_ship_vehicle_info),
67};
68
69static_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));
70
71Engine::Engine(VehicleType type, uint16_t local_id)
72{
73 this->type = type;
74 this->grf_prop.local_id = local_id;
75 this->list_position = local_id;
76 this->preview_company = CompanyID::Invalid();
77 this->display_last_variant = EngineID::Invalid();
78
79 /* Check if this base engine is within the original engine data range */
80 if (local_id >= _engine_counts[type]) {
81 /* Initialise default type-specific information. */
82 switch (type) {
83 case VEH_TRAIN: this->vehicle_info.emplace<RailVehicleInfo>(); break;
84 case VEH_ROAD: this->vehicle_info.emplace<RoadVehicleInfo>(); break;
85 case VEH_SHIP: this->vehicle_info.emplace<ShipVehicleInfo>(); break;
86 case VEH_AIRCRAFT: this->vehicle_info.emplace<AircraftVehicleInfo>(); break;
87 default: break;
88 }
89 /* Set model life to maximum to make wagons available */
90 this->info.base_life = TimerGameCalendar::Year{0xFF};
91 /* Aircraft must have CT_INVALID as default, as there is no property */
92 this->info.cargo_type = INVALID_CARGO;
93 this->info.cargo_label = (type == VEH_AIRCRAFT) ? CT_INVALID : CT_PASSENGERS;
94 /* Set cargo aging period to the default value. */
96 /* Not a variant */
97 this->info.variant_id = EngineID::Invalid();
98 return;
99 }
100
101 /* Copy the original engine info for this slot */
102 this->info = _orig_engine_info[_engine_offsets[type] + local_id];
103
104 /* Copy the original engine data for this slot */
105 switch (type) {
106 default: NOT_REACHED();
107
108 case VEH_TRAIN: {
109 RailVehicleInfo &rvi = this->vehicle_info.emplace<RailVehicleInfo>(_orig_rail_vehicle_info[local_id]);
110 this->original_image_index = rvi.image_index;
111 this->info.string_id = STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KIRBY_PAUL_TANK_STEAM + local_id;
112
113 /* Set the default model life of original wagons to "infinite" */
114 if (rvi.railveh_type == RAILVEH_WAGON) this->info.base_life = TimerGameCalendar::Year{0xFF};
115
116 break;
117 }
118
119 case VEH_ROAD: {
120 RoadVehicleInfo &rvi = this->vehicle_info.emplace<RoadVehicleInfo>(_orig_road_vehicle_info[local_id]);
121 this->original_image_index = rvi.image_index;
122 this->info.string_id = STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_REGAL_BUS + local_id;
123 break;
124 }
125
126 case VEH_SHIP: {
127 ShipVehicleInfo &svi = this->vehicle_info.emplace<ShipVehicleInfo>(_orig_ship_vehicle_info[local_id]);
128 this->original_image_index = svi.image_index;
129 this->info.string_id = STR_VEHICLE_NAME_SHIP_MPS_OIL_TANKER + local_id;
130 break;
131 }
132
133 case VEH_AIRCRAFT: {
134 AircraftVehicleInfo &avi = this->vehicle_info.emplace<AircraftVehicleInfo>(_orig_aircraft_vehicle_info[local_id]);
135 this->original_image_index = avi.image_index;
136 this->info.string_id = STR_VEHICLE_NAME_AIRCRAFT_SAMPSON_U52 + local_id;
137 break;
138 }
139 }
140}
141
147{
148 return this->info.string_id != STR_NEWGRF_INVALID_ENGINE && this->info.climates.Test(_settings_game.game_creation.landscape);
149}
150
156uint32_t Engine::GetGRFID() const
157{
158 const GRFFile *file = this->GetGRF();
159 return file == nullptr ? 0 : file->grfid;
160}
161
168{
169 /* For engines that can appear in a consist (i.e. rail vehicles and (articulated) road vehicles), a capacity
170 * of zero is a special case, to define the vehicle to not carry anything. The default cargotype is still used
171 * for livery selection etc.
172 * Note: Only the property is tested. A capacity callback returning 0 does not have the same effect.
173 */
174 switch (this->type) {
175 case VEH_TRAIN:
176 if (this->VehInfo<RailVehicleInfo>().capacity == 0) return false;
177 break;
178
179 case VEH_ROAD:
180 if (this->VehInfo<RoadVehicleInfo>().capacity == 0) return false;
181 break;
182
183 case VEH_SHIP:
184 case VEH_AIRCRAFT:
185 break;
186
187 default: NOT_REACHED();
188 }
190}
191
192
200uint Engine::DetermineCapacity(const Vehicle *v, uint16_t *mail_capacity) const
201{
202 assert(v == nullptr || this->index == v->engine_type);
203 if (mail_capacity != nullptr) *mail_capacity = 0;
204
205 if (!this->CanCarryCargo()) return 0;
206
207 bool new_multipliers = this->info.misc_flags.Test(EngineMiscFlag::NoDefaultCargoMultiplier);
208 CargoType default_cargo = this->GetDefaultCargoType();
209 CargoType cargo_type = (v != nullptr) ? v->cargo_type : default_cargo;
210
211 if (mail_capacity != nullptr && this->type == VEH_AIRCRAFT && IsCargoInClass(cargo_type, CargoClass::Passengers)) {
212 *mail_capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->VehInfo<AircraftVehicleInfo>().mail_capacity, v);
213 }
214
215 /* Check the refit capacity callback if we are not in the default configuration, or if we are using the new multiplier algorithm. */
217 (new_multipliers || default_cargo != cargo_type || (v != nullptr && v->cargo_subtype != 0))) {
218 uint16_t callback = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, this->index, v);
219 if (callback != CALLBACK_FAILED) return callback;
220 }
221
222 /* Get capacity according to property resp. CB */
223 uint capacity;
224 uint extra_mail_cap = 0;
225 switch (this->type) {
226 case VEH_TRAIN:
227 capacity = GetEngineProperty(this->index, PROP_TRAIN_CARGO_CAPACITY, this->VehInfo<RailVehicleInfo>().capacity, v);
228
229 /* In purchase list add the capacity of the second head. Always use the plain property for this. */
230 if (v == nullptr && this->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_MULTIHEAD) capacity += this->VehInfo<RailVehicleInfo>().capacity;
231 break;
232
233 case VEH_ROAD:
234 capacity = GetEngineProperty(this->index, PROP_ROADVEH_CARGO_CAPACITY, this->VehInfo<RoadVehicleInfo>().capacity, v);
235 break;
236
237 case VEH_SHIP:
238 capacity = GetEngineProperty(this->index, PROP_SHIP_CARGO_CAPACITY, this->VehInfo<ShipVehicleInfo>().capacity, v);
239 break;
240
241 case VEH_AIRCRAFT:
242 capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_PASSENGER_CAPACITY, this->VehInfo<AircraftVehicleInfo>().passenger_capacity, v);
243 if (!IsCargoInClass(cargo_type, CargoClass::Passengers)) {
244 extra_mail_cap = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->VehInfo<AircraftVehicleInfo>().mail_capacity, v);
245 }
246 if (IsValidCargoType(GetCargoTypeByLabel(CT_MAIL))) {
247 if (!new_multipliers && cargo_type == GetCargoTypeByLabel(CT_MAIL)) return capacity + extra_mail_cap;
248 }
249 default_cargo = GetCargoTypeByLabel(CT_PASSENGERS); // Always use 'passengers' wrt. cargo multipliers
250 break;
251
252 default: NOT_REACHED();
253 }
254
255 if (!new_multipliers) {
256 /* Use the passenger multiplier for mail as well */
257 capacity += extra_mail_cap;
258 extra_mail_cap = 0;
259 }
260
261 /* Apply multipliers depending on cargo- and vehicletype. */
262 if (new_multipliers || (this->type != VEH_SHIP && default_cargo != cargo_type)) {
263 uint16_t default_multiplier = new_multipliers ? 0x100 : CargoSpec::Get(default_cargo)->multiplier;
264 uint16_t cargo_multiplier = CargoSpec::Get(cargo_type)->multiplier;
265 capacity *= cargo_multiplier;
266 if (extra_mail_cap > 0 && IsValidCargoType(GetCargoTypeByLabel(CT_MAIL))) {
267 uint mail_multiplier = CargoSpec::Get(GetCargoTypeByLabel(CT_MAIL))->multiplier;
268 capacity += (default_multiplier * extra_mail_cap * cargo_multiplier + mail_multiplier / 2) / mail_multiplier;
269 }
270 capacity = (capacity + default_multiplier / 2) / default_multiplier;
271 }
272
273 return capacity;
274}
275
281{
282 Price base_price;
283 uint cost_factor;
284 switch (this->type) {
285 case VEH_ROAD:
286 base_price = this->VehInfo<RoadVehicleInfo>().running_cost_class;
287 if (base_price == INVALID_PRICE) return 0;
288 cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_RUNNING_COST_FACTOR, this->VehInfo<RoadVehicleInfo>().running_cost);
289 break;
290
291 case VEH_TRAIN:
292 base_price = this->VehInfo<RailVehicleInfo>().running_cost_class;
293 if (base_price == INVALID_PRICE) return 0;
294 cost_factor = GetEngineProperty(this->index, PROP_TRAIN_RUNNING_COST_FACTOR, this->VehInfo<RailVehicleInfo>().running_cost);
295 break;
296
297 case VEH_SHIP:
298 base_price = PR_RUNNING_SHIP;
299 cost_factor = GetEngineProperty(this->index, PROP_SHIP_RUNNING_COST_FACTOR, this->VehInfo<ShipVehicleInfo>().running_cost);
300 break;
301
302 case VEH_AIRCRAFT:
303 base_price = PR_RUNNING_AIRCRAFT;
304 cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_RUNNING_COST_FACTOR, this->VehInfo<AircraftVehicleInfo>().running_cost);
305 break;
306
307 default: NOT_REACHED();
308 }
309
310 return GetPrice(base_price, cost_factor, this->GetGRF(), -8);
311}
312
318{
319 Price base_price;
320 uint cost_factor;
321 switch (this->type) {
322 case VEH_ROAD:
323 base_price = PR_BUILD_VEHICLE_ROAD;
324 cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_COST_FACTOR, this->VehInfo<RoadVehicleInfo>().cost_factor);
325 break;
326
327 case VEH_TRAIN:
328 if (this->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON) {
329 base_price = PR_BUILD_VEHICLE_WAGON;
330 cost_factor = GetEngineProperty(this->index, PROP_TRAIN_COST_FACTOR, this->VehInfo<RailVehicleInfo>().cost_factor);
331 } else {
332 base_price = PR_BUILD_VEHICLE_TRAIN;
333 cost_factor = GetEngineProperty(this->index, PROP_TRAIN_COST_FACTOR, this->VehInfo<RailVehicleInfo>().cost_factor);
334 }
335 break;
336
337 case VEH_SHIP:
338 base_price = PR_BUILD_VEHICLE_SHIP;
339 cost_factor = GetEngineProperty(this->index, PROP_SHIP_COST_FACTOR, this->VehInfo<ShipVehicleInfo>().cost_factor);
340 break;
341
342 case VEH_AIRCRAFT:
343 base_price = PR_BUILD_VEHICLE_AIRCRAFT;
344 cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_COST_FACTOR, this->VehInfo<AircraftVehicleInfo>().cost_factor);
345 break;
346
347 default: NOT_REACHED();
348 }
349
350 return GetPrice(base_price, cost_factor, this->GetGRF(), -8);
351}
352
358{
359 switch (this->type) {
360 case VEH_TRAIN:
361 return GetEngineProperty(this->index, PROP_TRAIN_SPEED, this->VehInfo<RailVehicleInfo>().max_speed);
362
363 case VEH_ROAD: {
364 uint max_speed = GetEngineProperty(this->index, PROP_ROADVEH_SPEED, 0);
365 return (max_speed != 0) ? max_speed * 2 : this->VehInfo<RoadVehicleInfo>().max_speed / 2;
366 }
367
368 case VEH_SHIP:
369 return GetEngineProperty(this->index, PROP_SHIP_SPEED, this->VehInfo<ShipVehicleInfo>().max_speed) / 2;
370
371 case VEH_AIRCRAFT: {
372 uint max_speed = GetEngineProperty(this->index, PROP_AIRCRAFT_SPEED, 0);
373 if (max_speed != 0) {
374 return (max_speed * 128) / 10;
375 }
376 return this->VehInfo<AircraftVehicleInfo>().max_speed;
377 }
378
379 default: NOT_REACHED();
380 }
381}
382
390{
391 /* Only trains and road vehicles have 'power'. */
392 switch (this->type) {
393 case VEH_TRAIN:
394 return GetEngineProperty(this->index, PROP_TRAIN_POWER, this->VehInfo<RailVehicleInfo>().power);
395 case VEH_ROAD:
396 return GetEngineProperty(this->index, PROP_ROADVEH_POWER, this->VehInfo<RoadVehicleInfo>().power) * 10;
397
398 default: NOT_REACHED();
399 }
400}
401
408{
409 /* Only trains and road vehicles have 'weight'. */
410 switch (this->type) {
411 case VEH_TRAIN:
412 return GetEngineProperty(this->index, PROP_TRAIN_WEIGHT, this->VehInfo<RailVehicleInfo>().weight) << (this->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_MULTIHEAD ? 1 : 0);
413 case VEH_ROAD:
414 return GetEngineProperty(this->index, PROP_ROADVEH_WEIGHT, this->VehInfo<RoadVehicleInfo>().weight) / 4;
415
416 default: NOT_REACHED();
417 }
418}
419
426{
427 /* Only trains and road vehicles have 'tractive effort'. */
428 switch (this->type) {
429 case VEH_TRAIN:
430 return (GROUND_ACCELERATION * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_TRAIN_TRACTIVE_EFFORT, this->VehInfo<RailVehicleInfo>().tractive_effort)) / 256;
431 case VEH_ROAD:
432 return (GROUND_ACCELERATION * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_ROADVEH_TRACTIVE_EFFORT, this->VehInfo<RoadVehicleInfo>().tractive_effort)) / 256;
433
434 default: NOT_REACHED();
435 }
436}
437
443{
444 /* Assume leap years; this gives the player a bit more than the given amount of years, but never less. */
446}
447
452uint16_t Engine::GetRange() const
453{
454 switch (this->type) {
455 case VEH_AIRCRAFT:
456 return GetEngineProperty(this->index, PROP_AIRCRAFT_RANGE, this->VehInfo<AircraftVehicleInfo>().max_range);
457
458 default: NOT_REACHED();
459 }
460}
461
467{
468 switch (this->type) {
469 case VEH_AIRCRAFT:
470 switch (this->VehInfo<AircraftVehicleInfo>().subtype) {
471 case AIR_HELI: return STR_LIVERY_HELICOPTER;
472 case AIR_CTOL: return STR_LIVERY_SMALL_PLANE;
473 case AIR_CTOL | AIR_FAST: return STR_LIVERY_LARGE_PLANE;
474 default: NOT_REACHED();
475 }
476
477 default: NOT_REACHED();
478 }
479}
480
487{
488 /* In case company is spectator. */
489 if (c >= MAX_COMPANIES) return false;
490
491 /* Shortcut if this engine is explicitly hidden. */
492 if (this->IsHidden(c)) return true;
493
494 /* Check for hidden parent variants. This is a bit convoluted as we must check hidden status of
495 * the last display variant rather than the actual parent variant. */
496 const Engine *re = this;
497 const Engine *ve = re->GetDisplayVariant();
498 while (!(ve->IsHidden(c)) && re->info.variant_id != EngineID::Invalid()) {
499 re = Engine::Get(re->info.variant_id);
500 ve = re->GetDisplayVariant();
501 }
502 return ve->IsHidden(c);
503}
504
509{
510 EngineID id = EngineID::Begin();
511 for (VehicleType type = VEH_TRAIN; type <= VEH_AIRCRAFT; type++) {
512 auto &map = this->mappings[type];
513 map.clear();
514 for (uint internal_id = 0; internal_id < _engine_counts[type]; internal_id++, ++id) {
515 map.emplace_back(INVALID_GRFID, internal_id, type, internal_id, id);
516 }
517 }
518}
519
529EngineID EngineOverrideManager::GetID(VehicleType type, uint16_t grf_local_id, uint32_t grfid)
530{
531 const auto &map = this->mappings[type];
532 const auto key = EngineIDMapping::Key(grfid, grf_local_id);
533 auto it = std::ranges::lower_bound(map, key, std::less{}, EngineIDMappingKeyProjection{});
534 if (it == std::end(map) || it->Key() != key) return EngineID::Invalid();
535 return it->engine;
536}
537
548EngineID EngineOverrideManager::UseUnreservedID(VehicleType type, uint16_t grf_local_id, uint32_t grfid, bool static_access)
549{
550 auto &map = _engine_mngr.mappings[type];
551 const auto key = EngineIDMapping::Key(INVALID_GRFID, grf_local_id);
552 auto it = std::ranges::lower_bound(map, key, std::less{}, EngineIDMappingKeyProjection{});
553 if (it == std::end(map) || it->Key() != key) return EngineID::Invalid();
554
555 if (!static_access && grfid != INVALID_GRFID) {
556 /* Reserve the engine slot for the new grfid. */
557 it->grfid = grfid;
558
559 /* Relocate entry to its new position in the mapping list to keep it sorted. */
560 auto p = std::ranges::lower_bound(map, EngineIDMapping::Key(grfid, grf_local_id), std::less{}, EngineIDMappingKeyProjection{});
561 it = Slide(it, std::next(it), p).first;
562 }
563
564 return it->engine;
565}
566
567void EngineOverrideManager::SetID(VehicleType type, uint16_t grf_local_id, uint32_t grfid, uint8_t substitute_id, EngineID engine)
568{
569 auto &map = this->mappings[type];
570 const auto key = EngineIDMapping::Key(grfid, grf_local_id);
571 auto it = std::ranges::lower_bound(map, key, std::less{}, EngineIDMappingKeyProjection{});
572 if (it == std::end(map) || it->Key() != key) {
573 map.emplace(it, grfid, grf_local_id, type, substitute_id, engine);
574 } else {
575 it->engine = engine;
576 }
577}
578
585{
586 for (const Vehicle *v : Vehicle::Iterate()) {
587 if (IsCompanyBuildableVehicleType(v)) return false;
588 }
589
590 /* Reset the engines, they will get new EngineIDs */
591 _engine_mngr.ResetToDefaultMapping();
593
594 return true;
595}
596
601{
603 _engine_pool.CleanPool();
604
605 for (VehicleType type = VEH_BEGIN; type != VEH_COMPANY_END; type++) {
606 const auto &mapping = _engine_mngr.mappings[type];
607
608 /* Verify that the engine override manager has at least been set up with the default engines. */
609 assert(std::size(mapping) >= _engine_counts[type]);
610
611 for (const EngineIDMapping &eid : mapping) {
612 new (eid.engine) Engine(type, eid.internal_id);
613 }
614 }
615}
616
617void ShowEnginePreviewWindow(EngineID engine);
618
624static bool IsWagon(EngineID index)
625{
626 const Engine *e = Engine::Get(index);
627 return e->type == VEH_TRAIN && e->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON;
628}
629
635static void ClearLastVariant(EngineID engine_id, VehicleType type)
636{
637 for (Engine *e : Engine::IterateType(type)) {
638 if (e->display_last_variant == engine_id) e->display_last_variant = EngineID::Invalid();
639 }
640}
641
646void CalcEngineReliability(Engine *e, bool new_month)
647{
648 /* Get source engine for reliability age. This is normally our engine unless variant reliability syncing is requested. */
649 Engine *re = e;
650 while (re->info.variant_id != EngineID::Invalid() && re->info.extra_flags.Test(ExtraEngineFlag::SyncReliability)) {
651 re = Engine::Get(re->info.variant_id);
652 }
653
654 uint32_t age = re->age;
655 if (new_month && re->index > e->index && age != INT32_MAX) age++; /* parent variant's age has not yet updated. */
656
657 /* Check for early retirement */
658 if (e->company_avail.Any() && !_settings_game.vehicle.never_expire_vehicles && e->info.base_life != 0xFF) {
659 int retire_early = e->info.retire_early;
660 uint retire_early_max_age = std::max(0, e->duration_phase_1 + e->duration_phase_2 - retire_early * 12);
661 if (retire_early != 0 && age >= retire_early_max_age) {
662 /* Early retirement is enabled and we're past the date... */
666 }
667 }
668
669 if (age < e->duration_phase_1) {
670 uint start = e->reliability_start;
671 e->reliability = age * (e->reliability_max - start) / e->duration_phase_1 + start;
672 } else if ((age -= e->duration_phase_1) < e->duration_phase_2 || _settings_game.vehicle.never_expire_vehicles || e->info.base_life == 0xFF) {
673 /* We are at the peak of this engines life. It will have max reliability.
674 * This is also true if the engines never expire. They will not go bad over time */
676 } else if ((age -= e->duration_phase_2) < e->duration_phase_3) {
677 uint max = e->reliability_max;
678 e->reliability = (int)age * (int)(e->reliability_final - max) / e->duration_phase_3 + max;
679 } else {
680 /* time's up for this engine.
681 * We will now completely retire this design */
684 /* Kick this engine out of the lists */
687 }
688
689}
690
693{
694 /* Determine last engine aging year, default to 2050 as previously. */
696
697 for (const Engine *e : Engine::Iterate()) {
698 const EngineInfo *ei = &e->info;
699
700 /* Exclude certain engines */
702 if (e->type == VEH_TRAIN && e->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON) continue;
703
704 /* Base year ending date on half the model life */
705 TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(ei->base_intro + (ei->lifelength.base() * CalendarTime::DAYS_IN_LEAP_YEAR) / 2);
706
708 }
709}
710
717void StartupOneEngine(Engine *e, const TimerGameCalendar::YearMonthDay &aging_ymd, uint32_t seed)
718{
719 const EngineInfo *ei = &e->info;
720
721 e->age = 0;
722 e->flags = {};
725
726 /* Vehicles with the same base_intro date shall be introduced at the same time.
727 * Make sure they use the same randomisation of the date. */
728 SavedRandomSeeds saved_seeds;
729 SaveRandomSeeds(&saved_seeds);
731 ei->base_intro.base() ^
732 e->type ^
733 e->GetGRFID());
734 uint32_t r = Random();
735
736 /* Don't randomise the start-date in the first two years after gamestart to ensure availability
737 * of engines in early starting games.
738 * Note: TTDP uses fixed 1922 */
741 TimerGameCalendar::YearMonthDay intro_ymd = TimerGameCalendar::ConvertDateToYMD(e->intro_date);
742 int aging_months = aging_ymd.year.base() * 12 + aging_ymd.month;
743 int intro_months = intro_ymd.year.base() * 12 + intro_ymd.month;
744 if (intro_ymd.day > 1) intro_months++; // Engines are introduced at the first month start at/after intro date.
745 e->age = aging_months - intro_months;
746 e->company_avail.Set();
748 }
749
750 /* Get parent variant index for syncing reliability via random seed. */
751 const Engine *re = e;
752 while (re->info.variant_id != EngineID::Invalid() && re->info.extra_flags.Test(ExtraEngineFlag::SyncReliability)) {
753 re = Engine::Get(re->info.variant_id);
754 }
755
757 (re->index.base() << 16) ^ (re->info.base_intro.base() << 12) ^ (re->info.decay_speed << 8) ^
758 (re->info.lifelength.base() << 4) ^ re->info.retire_early ^
759 e->type ^
760 e->GetGRFID());
761
762 /* Base reliability defined as a percentage of UINT16_MAX. */
763 const uint16_t RELIABILITY_START = UINT16_MAX * 48 / 100;
764 const uint16_t RELIABILITY_MAX = UINT16_MAX * 75 / 100;
765 const uint16_t RELIABILITY_FINAL = UINT16_MAX * 25 / 100;
766
767 static_assert(RELIABILITY_START == 0x7AE0);
768 static_assert(RELIABILITY_MAX == 0xBFFF);
769 static_assert(RELIABILITY_FINAL == 0x3FFF);
770
771 r = Random();
772 /* 14 bits gives a value between 0 and 16383, which is up to an additional 25%p reliability on top of the base reliability. */
773 e->reliability_start = GB(r, 16, 14) + RELIABILITY_START;
774 e->reliability_max = GB(r, 0, 14) + RELIABILITY_MAX;
775
776 r = Random();
777 e->reliability_final = GB(r, 16, 14) + RELIABILITY_FINAL;
778
779 e->duration_phase_1 = GB(r, 0, 5) + 7;
780 e->duration_phase_2 = std::max(0, int(GB(r, 5, 4)) + ei->base_life.base() * 12 - 96);
781 e->duration_phase_3 = GB(r, 9, 7) + 120;
782
783 RestoreRandomSeeds(saved_seeds);
784
785 e->reliability_spd_dec = ei->decay_speed << 2;
786
787 /* prevent certain engines from ever appearing. */
791 }
792}
793
799{
800 /* Aging of vehicles stops, so account for that when starting late */
802 TimerGameCalendar::YearMonthDay aging_ymd = TimerGameCalendar::ConvertDateToYMD(aging_date);
803 uint32_t seed = Random();
804
805 for (Engine *e : Engine::Iterate()) {
806 StartupOneEngine(e, aging_ymd, seed);
807 }
808 for (Engine *e : Engine::Iterate()) {
809 CalcEngineReliability(e, false);
810 }
811
812 /* Update the bitmasks for the vehicle lists */
813 for (Company *c : Company::Iterate()) {
814 c->avail_railtypes = GetCompanyRailTypes(c->index);
815 c->avail_roadtypes = GetCompanyRoadTypes(c->index);
816 }
817
818 /* Invalidate any open purchase lists */
820
823}
824
831{
832 Engine *e = Engine::Get(eid);
833 Company *c = Company::Get(company);
834
835 e->company_avail.Set(company);
836 if (e->type == VEH_TRAIN) {
838 } else if (e->type == VEH_ROAD) {
840 }
841
842 if (company == _local_company) {
844
845 /* Update the toolbar. */
850 }
851}
852
859{
860 Engine *e = Engine::Get(eid);
861 Company *c = Company::Get(company);
862
863 e->company_avail.Reset(company);
864 if (e->type == VEH_TRAIN) {
866 } else if (e->type == VEH_ROAD) {
868 }
869
870 if (company == _local_company) {
873 }
874}
875
882static void AcceptEnginePreview(EngineID eid, CompanyID company, int recursion_depth = 0)
883{
884 Engine *e = Engine::Get(eid);
885
886 e->preview_company = CompanyID::Invalid();
887 e->preview_asked.Set();
888
889 EnableEngineForCompany(eid, company);
890
891 /* Notify preview window, that it might want to close.
892 * Note: We cannot directly close the window.
893 * In singleplayer this function is called from the preview window, so
894 * we have to use the GUI-scope scheduling of InvalidateWindowData.
895 */
897
898 /* Don't search for variants to include if we are 10 levels deep already. */
899 if (recursion_depth >= 10) return;
900
901 /* Find variants to be included in preview. */
902 for (Engine *ve : Engine::IterateType(e->type)) {
903 if (ve->index != eid && ve->info.variant_id == eid && ve->info.extra_flags.Test(ExtraEngineFlag::JoinPreview)) {
904 AcceptEnginePreview(ve->index, company, recursion_depth + 1);
905 }
906 }
907}
908
915{
916 CompanyID best_company = CompanyID::Invalid();
917
918 /* For trains the cargomask has no useful meaning, since you can attach other wagons */
919 CargoTypes cargomask = e->type != VEH_TRAIN ? GetUnionOfArticulatedRefitMasks(e->index, true) : ALL_CARGOTYPES;
920
921 int32_t best_hist = -1;
922 for (const Company *c : Company::Iterate()) {
923 if (c->block_preview == 0 && !e->preview_asked.Test(c->index) &&
924 c->old_economy[0].performance_history > best_hist) {
925
926 /* Check whether the company uses similar vehicles */
927 for (const Vehicle *v : Vehicle::Iterate()) {
928 if (v->owner != c->index || v->type != e->type) continue;
929 if (!v->GetEngine()->CanCarryCargo() || !HasBit(cargomask, v->cargo_type)) continue;
930
931 best_hist = c->old_economy[0].performance_history;
932 best_company = c->index;
933 break;
934 }
935 }
936 }
937
938 return best_company;
939}
940
948static bool IsVehicleTypeDisabled(VehicleType type, bool ai)
949{
950 switch (type) {
955
956 default: NOT_REACHED();
957 }
958}
959
961static const IntervalTimer<TimerGameCalendar> _calendar_engines_daily({TimerGameCalendar::DAY, TimerGameCalendar::Priority::ENGINE}, [](auto)
962{
963 for (Company *c : Company::Iterate()) {
964 c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes, TimerGameCalendar::date);
965 c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes, TimerGameCalendar::date);
966 }
967
969
970 for (Engine *e : Engine::Iterate()) {
971 EngineID i = e->index;
972 if (e->flags.Test(EngineFlag::ExclusivePreview)) {
973 if (e->preview_company != CompanyID::Invalid()) {
974 if (!--e->preview_wait) {
976 e->preview_company = CompanyID::Invalid();
977 }
978 } else if (e->preview_asked.Count() < MAX_COMPANIES) {
979 e->preview_company = GetPreviewCompany(e);
980
981 if (e->preview_company == CompanyID::Invalid()) {
982 e->preview_asked.Set();
983 continue;
984 }
985
986 e->preview_asked.Set(e->preview_company);
987 e->preview_wait = 20;
988 /* AIs are intentionally not skipped for preview even if they cannot build a certain
989 * vehicle type. This is done to not give poor performing human companies an "unfair"
990 * boost that they wouldn't have gotten against other human companies. The check on
991 * the line below is just to make AIs not notice that they have a preview if they
992 * cannot build the vehicle. */
993 if (!IsVehicleTypeDisabled(e->type, true)) AI::NewEvent(e->preview_company, new ScriptEventEnginePreview(i));
994 if (IsInteractiveCompany(e->preview_company)) ShowEnginePreviewWindow(i);
995 }
996 }
997 }
998});
999
1005{
1006 for (Engine *e : Engine::Iterate()) {
1007 e->company_hidden.Reset(cid);
1008 }
1009}
1010
1019{
1020 Engine *e = Engine::GetIfValid(engine_id);
1021 if (e == nullptr || _current_company >= MAX_COMPANIES) return CMD_ERROR;
1023
1024 if (flags.Test(DoCommandFlag::Execute)) {
1027 }
1028
1029 return CommandCost();
1030}
1031
1040{
1041 Engine *e = Engine::GetIfValid(engine_id);
1042 if (e == nullptr || !e->flags.Test(EngineFlag::ExclusivePreview) || e->preview_company != _current_company) return CMD_ERROR;
1043
1045
1046 return CommandCost();
1047}
1048
1057CommandCost CmdEngineCtrl(DoCommandFlags flags, EngineID engine_id, CompanyID company_id, bool allow)
1058{
1059 if (_current_company != OWNER_DEITY) return CMD_ERROR;
1060
1061 if (!Engine::IsValidID(engine_id) || !Company::IsValidID(company_id)) return CMD_ERROR;
1062
1063 if (flags.Test(DoCommandFlag::Execute)) {
1064 if (allow) {
1065 EnableEngineForCompany(engine_id, company_id);
1066 } else {
1067 DisableEngineForCompany(engine_id, company_id);
1068 }
1069 }
1070
1071 return CommandCost();
1072}
1073
1080{
1081 EngineID index = e->index;
1082
1083 /* In case the company didn't build the vehicle during the intro period,
1084 * prevent that company from getting future intro periods for a while. */
1086 for (Company *c : Company::Iterate()) {
1087 if (!e->company_avail.Test(c->index)) continue;
1088
1089 /* Check the company's 'ALL_GROUP' group statistics. This only includes countable vehicles, which is fine
1090 * as those are the only engines that can be given exclusive previews. */
1091 if (GetGroupNumEngines(c->index, ALL_GROUP, e->index) == 0) {
1092 /* The company did not build this engine during preview. */
1093 c->block_preview = 20;
1094 }
1095 }
1096 }
1097
1100
1101 /* Now available for all companies */
1102 e->company_avail.Set();
1103
1104 /* Do not introduce new rail wagons */
1105 if (IsWagon(index)) return;
1106
1107 if (e->type == VEH_TRAIN) {
1108 /* maybe make another rail type available */
1109 assert(e->VehInfo<RailVehicleInfo>().railtypes != RailTypes{});
1111 for (Company *c : Company::Iterate()) c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | introduced, TimerGameCalendar::date);
1112 } else if (e->type == VEH_ROAD) {
1113 /* maybe make another road type available */
1114 assert(e->VehInfo<RoadVehicleInfo>().roadtype < ROADTYPE_END);
1115 for (Company *c : Company::Iterate()) c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes | GetRoadTypeInfo(e->VehInfo<RoadVehicleInfo>().roadtype)->introduces_roadtypes, TimerGameCalendar::date);
1116 }
1117
1118 /* Only broadcast event if AIs are able to build this vehicle type. */
1119 if (!IsVehicleTypeDisabled(e->type, true)) AI::BroadcastNewEvent(new ScriptEventEngineAvailable(index));
1120
1121 /* Only provide the "New Vehicle available" news paper entry, if engine can be built. */
1122 if (!IsVehicleTypeDisabled(e->type, false) && !e->info.extra_flags.Test(ExtraEngineFlag::NoNews)) {
1123 AddNewsItem(GetEncodedString(STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE,
1124 GetEngineCategoryName(index),
1127 }
1128
1129 /* Update the toolbar. */
1133
1134 /* Close pending preview windows */
1136}
1137
1140{
1142 bool refresh = false;
1143 for (Engine *e : Engine::Iterate()) {
1144 /* Age the vehicle */
1145 if (e->flags.Test(EngineFlag::Available) && e->age != INT32_MAX) {
1146 e->age++;
1147 CalcEngineReliability(e, true);
1148 refresh = true;
1149 }
1150
1151 /* Do not introduce invalid engines */
1152 if (!e->IsEnabled()) continue;
1153
1154 if (!e->flags.Test(EngineFlag::Available) && TimerGameCalendar::date >= (e->intro_date + CalendarTime::DAYS_IN_YEAR)) {
1155 /* Introduce it to all companies */
1157 } else if (!e->flags.Any({EngineFlag::Available, EngineFlag::ExclusivePreview}) && TimerGameCalendar::date >= e->intro_date) {
1158 /* Introduction date has passed...
1159 * Check if it is allowed to build this vehicle type at all
1160 * based on the current game settings. If not, it does not
1161 * make sense to show the preview dialog to any company. */
1162 if (IsVehicleTypeDisabled(e->type, false)) continue;
1163
1164 /* Do not introduce new rail wagons */
1165 if (IsWagon(e->index)) continue;
1166
1167 /* Engine has no preview */
1168 if (e->info.extra_flags.Test(ExtraEngineFlag::NoPreview)) continue;
1169
1170 /* Show preview dialog to one of the companies. */
1171 e->flags.Set(EngineFlag::ExclusivePreview);
1172 e->preview_company = CompanyID::Invalid();
1173 e->preview_asked = CompanyMask{};
1174 }
1175 }
1176
1177 InvalidateWindowClassesData(WC_BUILD_VEHICLE); // rebuild the purchase list (esp. when sorted by reliability)
1178
1179 if (refresh) {
1182 }
1183 }
1184}
1185
1186static const IntervalTimer<TimerGameCalendar> _calendar_engines_monthly({TimerGameCalendar::MONTH, TimerGameCalendar::Priority::ENGINE}, [](auto)
1187{
1189});
1190
1196static bool IsUniqueEngineName(const std::string &name)
1197{
1198 for (const Engine *e : Engine::Iterate()) {
1199 if (!e->name.empty() && e->name == name) return false;
1200 }
1201
1202 return true;
1203}
1204
1212CommandCost CmdRenameEngine(DoCommandFlags flags, EngineID engine_id, const std::string &text)
1213{
1214 Engine *e = Engine::GetIfValid(engine_id);
1215 if (e == nullptr) return CMD_ERROR;
1216
1217 bool reset = text.empty();
1218
1219 if (!reset) {
1221 if (!IsUniqueEngineName(text)) return CommandCost(STR_ERROR_NAME_MUST_BE_UNIQUE);
1222 }
1223
1224 if (flags.Test(DoCommandFlag::Execute)) {
1225 if (reset) {
1226 e->name.clear();
1227 } else {
1228 e->name = text;
1229 }
1230
1232 }
1233
1234 return CommandCost();
1235}
1236
1237
1247{
1248 const Engine *e = Engine::GetIfValid(engine);
1249
1250 /* check if it's an engine that is in the engine array */
1251 if (e == nullptr) return false;
1252
1253 /* check if it's an engine of specified type */
1254 if (e->type != type) return false;
1255
1256 /* check if it's available ... */
1257 if (company == OWNER_DEITY) {
1258 /* ... for any company (preview does not count) */
1259 if (!e->flags.Test(EngineFlag::Available) || e->company_avail.None()) return false;
1260 } else {
1261 /* ... for this company */
1262 if (!e->company_avail.Test(company)) return false;
1263 }
1264
1265 if (!e->IsEnabled()) return false;
1266
1267 if (type == VEH_TRAIN && company != OWNER_DEITY) {
1268 /* Check if the rail type is available to this company */
1269 const Company *c = Company::Get(company);
1270 if (!GetAllCompatibleRailTypes(e->VehInfo<RailVehicleInfo>().railtypes).Any(c->avail_railtypes)) return false;
1271 }
1272 if (type == VEH_ROAD && company != OWNER_DEITY) {
1273 /* Check if the road type is available to this company */
1274 const Company *c = Company::Get(company);
1275 if (!GetRoadTypeInfo(e->VehInfo<RoadVehicleInfo>().roadtype)->powered_roadtypes.Any(c->avail_roadtypes)) return false;
1276 }
1277
1278 return true;
1279}
1280
1288{
1289 const Engine *e = Engine::GetIfValid(engine);
1290
1291 /* check if it's an engine that is in the engine array */
1292 if (e == nullptr) return false;
1293
1294 if (!e->CanCarryCargo()) return false;
1295
1296 const EngineInfo *ei = &e->info;
1297 if (ei->refit_mask == 0) return false;
1298
1299 /* Are there suffixes?
1300 * Note: This does not mean the suffixes are actually available for every consist at any time. */
1302
1303 /* Is there any cargo except the default cargo? */
1304 CargoType default_cargo = e->GetDefaultCargoType();
1305 CargoTypes default_cargo_mask = 0;
1306 SetBit(default_cargo_mask, default_cargo);
1307 return IsValidCargoType(default_cargo) && ei->refit_mask != default_cargo_mask;
1308}
1309
1314{
1315 TimerGameCalendar::Date min_date{INT32_MAX};
1316
1317 for (const Engine *e : Engine::Iterate()) {
1318 if (!e->IsEnabled()) continue;
1319
1320 /* Don't consider train wagons, we need a powered engine available. */
1321 if (e->type == VEH_TRAIN && e->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON) continue;
1322
1323 /* We have an available engine... yay! */
1324 if (e->flags.Test(EngineFlag::Available) && e->company_avail.Any()) return;
1325
1326 /* Okay, try to find the earliest date. */
1327 min_date = std::min(min_date, e->info.base_intro);
1328 }
1329
1330 if (min_date < INT32_MAX) {
1331 ShowErrorMessage(GetEncodedString(STR_ERROR_NO_VEHICLES_AVAILABLE_YET),
1332 GetEncodedString(STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION, min_date), WL_WARNING);
1333 } else {
1334 ShowErrorMessage(GetEncodedString(STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL),
1335 GetEncodedString(STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION), WL_WARNING);
1336 }
1337}
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.
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
debug_inline 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
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:23
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:106
static constexpr CargoLabel CT_PASSENGERS
Available types of cargo Labels may be re-used between different climates.
Definition cargo_type.h:31
@ Passengers
Passengers.
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:255
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 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:466
uint GetPower() const
Returns the power of the engine for display and sorting purposes.
Definition engine.cpp:389
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:452
uint32_t GetGRFID() const
Retrieve the GRF ID of the NewGRF the engine is tied to.
Definition engine.cpp:156
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:317
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.
CargoGRFFileProps grf_prop
Link to NewGRF.
Definition engine_base.h:71
uint GetDisplayMaxSpeed() const
Returns max speed of the engine for display purposes.
Definition engine.cpp:357
uint DetermineCapacity(const Vehicle *v, uint16_t *mail_capacity=nullptr) const
Determines capacity of a given vehicle from scratch.
Definition engine.cpp:200
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:407
uint8_t original_image_index
Original vehicle image index, thus the image index of the overridden vehicle.
Definition engine_base.h:61
bool IsEnabled() const
Checks whether the engine is a valid (non-articulated part of an) engine.
Definition engine.cpp:146
VehicleType type
Vehicle type, ie VEH_ROAD, VEH_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:486
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:442
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:95
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:280
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:425
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:167
std::string name
Custom name of engine.
Definition engine_base.h:44
EngineID display_last_variant
NOSAVE client-side-only last variant selected.
Definition engine_base.h:65
uint16_t duration_phase_1
First reliability phase in months, increasing reliability from reliability_start to reliability_max.
Definition engine_base.h:54
Enum-as-bit-set wrapper.
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:111
RoadTypes introduces_roadtypes
Bitmask of which other roadtypes are introduced when this roadtype is introduced.
Definition road.h:166
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.
static constexpr int DAYS_IN_YEAR
days per year
static constexpr int DAYS_IN_LEAP_YEAR
sometimes, you need one day more...
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:949
Price
Enumeration of all base prices for use with Prices.
void ClearEnginesHiddenFlagOfCompany(CompanyID cid)
Clear the 'hidden' flag for all engines of a new company.
Definition engine.cpp:1004
void SetYearEngineAgingStops()
Compute the value for _year_engine_aging_stops.
Definition engine.cpp:692
static void NewVehicleAvailable(Engine *e)
An engine has become available for general use.
Definition engine.cpp:1079
const uint8_t _engine_counts[4]
Number of engines of each vehicle type in original engine data.
Definition engine.cpp:54
void SetupEngines()
Initialise the engine pool with the data from the original vehicles.
Definition engine.cpp:600
static CompanyID GetPreviewCompany(Engine *e)
Get the best company for an engine preview.
Definition engine.cpp:914
const uint8_t _engine_offsets[4]
Offset of the first engine of each vehicle type in original engine data.
Definition engine.cpp:62
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:635
static bool IsVehicleTypeDisabled(VehicleType type, bool ai)
Checks if a vehicle type is disabled for all/ai companies.
Definition engine.cpp:948
static void AcceptEnginePreview(EngineID eid, CompanyID company, int recursion_depth=0)
Company company accepts engine eid for preview.
Definition engine.cpp:882
CommandCost CmdRenameEngine(DoCommandFlags flags, EngineID engine_id, const std::string &text)
Rename an engine.
Definition engine.cpp:1212
CommandCost CmdWantEnginePreview(DoCommandFlags flags, EngineID engine_id)
Accept an engine prototype.
Definition engine.cpp:1039
void CalendarEnginesMonthlyLoop()
Monthly update of the availability, reliability, and preview offers of the engines.
Definition engine.cpp:1139
static bool IsUniqueEngineName(const std::string &name)
Is name still free as name for an engine?
Definition engine.cpp:1196
bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company)
Check if an engine is buildable.
Definition engine.cpp:1246
static const IntervalTimer< TimerGameCalendar > _calendar_engines_daily({TimerGameCalendar::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) { CloseWindowById(WC_ENGINE_PREVIEW, i);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 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:858
void StartupEngines()
Start/initialise all our engines.
Definition engine.cpp:798
static bool IsWagon(EngineID index)
Determine whether an engine type is a wagon (and not a loco).
Definition engine.cpp:624
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:1057
void StartupOneEngine(Engine *e, const TimerGameCalendar::YearMonthDay &aging_ymd, uint32_t seed)
Start/initialise one engine.
Definition engine.cpp:717
void CheckEngines()
Check for engines that have an appropriate availability.
Definition engine.cpp:1313
bool IsEngineRefittable(EngineID engine)
Check if an engine is refittable.
Definition engine.cpp:1287
CommandCost CmdSetVehicleVisibility(DoCommandFlags flags, EngineID engine_id, bool hide)
Set the visibility of an engine.
Definition engine.cpp:1018
void CalcEngineReliability(Engine *e, bool new_month)
Update Engine::reliability and (if needed) update the engine GUIs.
Definition engine.cpp:646
static void EnableEngineForCompany(EngineID eid, CompanyID company)
Allows engine eid to be used by a company company.
Definition engine.cpp:830
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'.
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 dparam.
@ 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.
@ RAILVEH_WAGON
simple wagon, not motorized
Definition engine_type.h:34
@ RAILVEH_MULTIHEAD
indicates a combination of two locomotives
Definition engine_type.h:33
This file contains all the data for vehicles.
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:1547
static constexpr GroupID ALL_GROUP
All vehicles are in this group.
Definition group_type.h:17
@ Random
Randomise borders.
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:902
@ NewVehicles
New vehicle has become available.
@ Vehicle
Vehicle news item. (new engine available)
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:135
RailTypes AddDateIntroducedRailTypes(RailTypes current, TimerGameCalendar::Date date)
Add the rail types that are to be introduced at the given date.
Definition rail.cpp:102
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
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:230
@ 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:350
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.
bool ai_disable_veh_roadveh
disable types for AI
bool ai_disable_veh_ship
disable types for AI
bool ai_disable_veh_train
disable types for AI
bool ai_disable_veh_aircraft
disable types for AI
Information about a aircraft vehicle.
uint16_t multiplier
Capacity multiplier for vehicles. (8 fractional bits)
Definition cargotype.h:80
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:137
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.
uint16_t cargo_age_period
Number of ticks before carried cargo is aged.
TimerGameCalendar::Year base_life
Basic duration of engine availability (without random parts). 0xFF means infinite life.
LandscapeTypes climates
Climates supported by the engine.
EngineMiscFlags misc_flags
Miscellaneous flags.
EngineID variant_id
Engine variant ID. If set, will be treated specially in purchase lists.
StringID string_id
Default name of engine.
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:584
void ResetToDefaultMapping()
Initializes the EngineOverrideManager with the default engines.
Definition engine.cpp:508
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:548
EngineID GetID(VehicleType type, uint16_t grf_local_id, uint32_t grfid)
Looks up an EngineID in the EngineOverrideManager.
Definition engine.cpp:529
uint16_t local_id
id defined by the grf file for this entity
Dynamic data of a loaded NewGRF.
Definition newgrf.h:115
LandscapeType landscape
the landscape we're currently in
TimerGameCalendar::Year starting_year
starting date
uint32_t generation_seed
noise seed for world generation
AISettings ai
what may the AI do?
GameCreationSettings game_creation
settings used during the creation of a game (map)
VehicleSettings vehicle
options for vehicles
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static Titem * Get(auto index)
Returns Titem with given index.
Tindex index
Index of this pool item.
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
static Titem * GetIfValid(auto index)
Returns Titem with given index.
Base class for all pools.
void CleanPool() override
Virtual method that deletes all items in the pool.
Information about a rail vehicle.
Definition engine_type.h:74
RailTypes railtypes
Railtypes, mangled if elrail is disabled.
Definition engine_type.h:78
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
Templated helper to make a type-safe 'typedef' representing a single POD value.
UnitID max_ships
max ships in game per company
UnitID max_trains
max trains in game per company
uint8_t extend_vehicle_life
extend vehicle life by this many years
UnitID max_aircraft
max planes in game per company
UnitID max_roadveh
max trucks in game per company
bool never_expire_vehicles
never expire vehicles
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.
@ VEH_ROAD
Road vehicle type.
@ VEH_AIRCRAFT
Aircraft vehicle type.
@ VEH_SHIP
Ship vehicle type.
@ VEH_TRAIN
Train vehicle type.
@ VEH_COMPANY_END
Last company-ownable type.
static const int GROUND_ACCELERATION
Acceleration due to gravity, 9.8 m/s^2.
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Definition window.cpp:1193
void CloseWindowByClass(WindowClass cls, int data)
Close all windows of a given class.
Definition window.cpp:1205
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition window.cpp:3184
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:3276
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:3293
Window functions not directly related to making/drawing windows.
@ WC_BUILD_TOOLBAR
Build toolbar; Window numbers:
Definition window_type.h:78
@ 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:63
@ WC_BUILD_VEHICLE
Build vehicle; Window numbers: