1
/* $Id: engine.cpp 14268 2008-09-07 22:04:39Z rubidium $ */
1
/* $Id: engine.cpp 15765 2009-03-18 19:50:34Z rubidium $ */
3
/** @file engine.cpp */
3
/** @file engine.cpp Base for all engine handling. */
9
#include "player_base.h"
10
#include "player_func.h"
7
#include "company_func.h"
11
8
#include "command_func.h"
14
10
#include "variables.h"
16
11
#include "aircraft.h"
17
#include "newgrf_cargo.h"
12
#include "newgrf_engine.h"
19
14
#include "strings_func.h"
20
15
#include "gfx_func.h"
21
#include "functions.h"
16
#include "core/random_func.hpp"
22
17
#include "window_func.h"
23
18
#include "date_func.h"
24
#include "autoreplace_base.h"
25
19
#include "autoreplace_gui.h"
26
20
#include "string_func.h"
21
#include "oldpool_func.h"
23
#include "vehicle_func.h"
27
24
#include "settings_type.h"
29
26
#include "table/strings.h"
30
27
#include "table/engines.h"
32
Engine _engines[TOTAL_NUM_ENGINES];
33
EngineInfo _engine_info[TOTAL_NUM_ENGINES];
34
RailVehicleInfo _rail_vehicle_info[NUM_TRAIN_ENGINES];
35
ShipVehicleInfo _ship_vehicle_info[NUM_SHIP_ENGINES];
36
AircraftVehicleInfo _aircraft_vehicle_info[NUM_AIRCRAFT_ENGINES];
37
RoadVehicleInfo _road_vehicle_info[NUM_ROAD_ENGINES];
40
YEAR_ENGINE_AGING_STOPS = 2050,
29
DEFINE_OLD_POOL_GENERIC(Engine, Engine)
31
EngineOverrideManager _engine_mngr;
33
/** Year that engine aging stops. Engines will not reduce in reliability
34
* and no more engines will be introduced */
35
Year _year_engine_aging_stops;
37
/** Number of engines of each vehicle type in original engine data */
38
const uint8 _engine_counts[4] = {
39
lengthof(_orig_rail_vehicle_info),
40
lengthof(_orig_road_vehicle_info),
41
lengthof(_orig_ship_vehicle_info),
42
lengthof(_orig_aircraft_vehicle_info),
45
/** Offset of the first engine of each vehicle type in original engine data */
46
const uint8 _engine_offsets[4] = {
48
lengthof(_orig_rail_vehicle_info),
49
lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info),
50
lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info) + lengthof(_orig_ship_vehicle_info),
53
const uint EngineOverrideManager::NUM_DEFAULT_ENGINES = _engine_counts[VEH_TRAIN] + _engine_counts[VEH_ROAD] + _engine_counts[VEH_SHIP] + _engine_counts[VEH_AIRCRAFT];
62
Engine::Engine(VehicleType type, EngineID base)
65
this->internal_id = base;
66
this->list_position = base;
68
/* Check if this base engine is within the original engine data range */
69
if (base >= _engine_counts[type]) {
70
/* Mark engine as valid anyway */
71
this->info.climates = 0x80;
72
/* Set model life to maximum to make wagons available */
73
this->info.base_life = 0xFF;
77
/* Copy the original engine info for this slot */
78
this->info = _orig_engine_info[_engine_offsets[type] + base];
80
/* Copy the original engine data for this slot */
82
default: NOT_REACHED();
85
this->u.rail = _orig_rail_vehicle_info[base];
86
this->image_index = this->u.rail.image_index;
87
this->info.string_id = STR_8000_KIRBY_PAUL_TANK_STEAM + base;
89
/* Set the default model life of original wagons to "infinite" */
90
if (this->u.rail.railveh_type == RAILVEH_WAGON) this->info.base_life = 0xFF;
95
this->u.road = _orig_road_vehicle_info[base];
96
this->image_index = this->u.road.image_index;
97
this->info.string_id = STR_8074_MPS_REGAL_BUS + base;
101
this->u.ship = _orig_ship_vehicle_info[base];
102
this->image_index = this->u.ship.image_index;
103
this->info.string_id = STR_80CC_MPS_OIL_TANKER + base;
107
this->u.air = _orig_aircraft_vehicle_info[base];
108
this->image_index = this->u.air.image_index;
109
this->info.string_id = STR_80D7_SAMPSON_U52 + base;
116
UnloadWagonOverrides(this);
121
* Determines the default cargo type of an engine.
123
* Usually a valid cargo is returned, even though the vehicle has zero capacity, and can therefore not carry anything. But the cargotype is still used
124
* for livery selection etc..
126
* Vehicles with CT_INVALID as default cargo are usally not available, but it can appear as default cargo of articulated parts.
128
* @return The default cargo type.
131
CargoID Engine::GetDefaultCargoType() const
133
switch (this->type) {
135
return this->u.rail.cargo_type;
138
return this->u.road.cargo_type;
141
return this->u.ship.cargo_type;
144
return FindFirstRefittableCargo(this->index);
146
default: NOT_REACHED();
151
* Determines whether an engine can carry something.
152
* A vehicle cannot carry anything if its capacity is zero, or none of the possible cargos is available in the climate.
153
* @return true if the vehicle can carry something.
155
bool Engine::CanCarryCargo() const
157
/* For engines that can appear in a consist (i.e. rail vehicles and (articulated) road vehicles), a capacity
158
* of zero is a special case, to define the vehicle to not carry anything. The default cargotype is still used
159
* for livery selection etc.
160
* Note: Only the property is tested. A capacity callback returning 0 does not have the same effect.
162
switch (this->type) {
164
if (this->u.rail.capacity == 0) return false;
168
if (this->u.road.capacity == 0) return false;
175
default: NOT_REACHED();
177
return this->GetDefaultCargoType() != CT_INVALID;
181
* Determines the default cargo capacity of an engine for display purposes.
183
* For planes carrying both passenger and mail this is the passenger capacity.
184
* For multiheaded engines this is the capacity of both heads.
185
* For articulated engines use GetCapacityOfArticulatedParts
187
* @return The default capacity
188
* @see GetDefaultCargoType
190
uint Engine::GetDisplayDefaultCapacity() const
192
if (!this->CanCarryCargo()) return 0;
195
return GetEngineProperty(this->index, 0x14, this->u.rail.capacity) + (this->u.rail.railveh_type == RAILVEH_MULTIHEAD ? this->u.rail.capacity : 0);
198
return GetEngineProperty(this->index, 0x0F, this->u.road.capacity);
201
return GetEngineProperty(this->index, 0x0D, this->u.ship.capacity);
204
return AircraftDefaultCargoCapacity(this->GetDefaultCargoType(), &this->u.air);
206
default: NOT_REACHED();
210
Money Engine::GetRunningCost() const
212
switch (this->type) {
214
return this->u.road.running_cost * GetPriceByIndex(this->u.road.running_cost_class) >> 8;
217
return GetEngineProperty(this->index, 0x0D, this->u.rail.running_cost) * GetPriceByIndex(this->u.rail.running_cost_class) >> 8;
220
return GetEngineProperty(this->index, 0x0F, this->u.ship.running_cost) * _price.ship_running >> 8;
223
return GetEngineProperty(this->index, 0x0E, this->u.air.running_cost) * _price.aircraft_running >> 8;
225
default: NOT_REACHED();
229
Money Engine::GetCost() const
231
switch (this->type) {
233
return GetEngineProperty(this->index, 0x11, this->u.road.cost_factor) * (_price.roadveh_base >> 3) >> 5;
236
if (this->u.rail.railveh_type == RAILVEH_WAGON) {
237
return (GetEngineProperty(this->index, 0x17, this->u.rail.cost_factor) * _price.build_railwagon) >> 8;
239
return GetEngineProperty(this->index, 0x17, this->u.rail.cost_factor) * (_price.build_railvehicle >> 3) >> 5;
242
return GetEngineProperty(this->index, 0x0A, this->u.ship.cost_factor) * (_price.ship_base >> 3) >> 5;
245
return GetEngineProperty(this->index, 0x0B, this->u.air.cost_factor) * (_price.aircraft_base >> 3) >> 5;
247
default: NOT_REACHED();
252
* Returns max speed for display purposes
253
* @return max speed in km-ish/h
255
uint Engine::GetDisplayMaxSpeed() const
257
switch (this->type) {
259
return GetEngineProperty(this->index, 0x09, this->u.rail.max_speed);
262
return this->u.road.max_speed / 2;
265
return GetEngineProperty(this->index, 0x0B, this->u.ship.max_speed) / 2;
268
return this->u.air.max_speed;
270
default: NOT_REACHED();
274
uint Engine::GetPower() const
276
/* Currently only trains have 'power' */
277
switch (this->type) {
279
return GetEngineProperty(this->index, 0x0B, this->u.rail.power);
281
default: NOT_REACHED();
286
* Returns the weight for display purposes.
287
* For dual-headed train-engines this is the weight of both heads
288
* @return weight in display units metric tons
290
uint Engine::GetDisplayWeight() const
292
/* Currently only trains have 'weight' */
293
switch (this->type) {
295
return GetEngineProperty(this->index, 0x16, this->u.rail.weight) << (this->u.rail.railveh_type == RAILVEH_MULTIHEAD ? 1 : 0);
297
default: NOT_REACHED();
302
* Returns the tractive effort for display purposes.
303
* For dual-headed train-engines this is the tractive effort of both heads
304
* @return tractive effort in display units kN
306
uint Engine::GetDisplayMaxTractiveEffort() const
308
/* Currently only trains have 'tractive effort' */
309
switch (this->type) {
311
return (10 * this->GetDisplayWeight() * GetEngineProperty(this->index, 0x1F, this->u.rail.tractive_effort)) / 256;
313
default: NOT_REACHED();
318
* Initializes the EngineOverrideManager with the default engines.
320
void EngineOverrideManager::ResetToDefaultMapping()
323
for (VehicleType type = VEH_TRAIN; type <= VEH_AIRCRAFT; type++) {
324
for (uint internal_id = 0; internal_id < _engine_counts[type]; internal_id++) {
325
EngineIDMapping *eid = this->Append();
327
eid->grfid = INVALID_GRFID;
328
eid->internal_id = internal_id;
329
eid->substitute_id = internal_id;
335
* Looks up an EngineID in the EngineOverrideManager
336
* @param type Vehicle type
337
* @param grf_local_id The local id in the newgrf
338
* @param grfid The GrfID that defines the scope of grf_local_id.
339
* If a newgrf overrides the engines of another newgrf, the "scope grfid" is the ID of the overridden newgrf.
340
* If dynnamic_engines is disabled, all newgrf share the same ID scope identified by INVALID_GRFID.
341
* @return The engine ID if present, or INVALID_ENGINE if not.
343
EngineID EngineOverrideManager::GetID(VehicleType type, uint16 grf_local_id, uint32 grfid)
345
const EngineIDMapping *end = this->End();
347
for (const EngineIDMapping *eid = this->Begin(); eid != end; eid++, index++) {
348
if (eid->type == type && eid->grfid == grfid && eid->internal_id == grf_local_id) {
352
return INVALID_ENGINE;
355
/** Sets cached values in Company::num_vehicles and Group::num_vehicles
357
void SetCachedEngineCounts()
359
uint engines = GetEnginePoolSize();
361
/* Set up the engine count for all companies */
363
FOR_ALL_COMPANIES(c) {
364
free(c->num_engines);
365
c->num_engines = CallocT<EngineID>(engines);
371
free(g->num_engines);
372
g->num_engines = CallocT<EngineID>(engines);
376
FOR_ALL_VEHICLES(v) {
377
if (!IsEngineCountable(v)) continue;
379
assert(v->engine_type < engines);
381
GetCompany(v->owner)->num_engines[v->engine_type]++;
383
if (v->group_id == DEFAULT_GROUP) continue;
385
g = GetGroup(v->group_id);
386
assert(v->type == g->vehicle_type);
387
assert(v->owner == g->owner);
389
g->num_engines[v->engine_type]++;
44
393
void SetupEngines()
46
/* Copy original static engine data */
47
memcpy(&_engine_info, &_orig_engine_info, sizeof(_orig_engine_info));
48
memcpy(&_rail_vehicle_info, &_orig_rail_vehicle_info, sizeof(_orig_rail_vehicle_info));
49
memcpy(&_ship_vehicle_info, &_orig_ship_vehicle_info, sizeof(_orig_ship_vehicle_info));
50
memcpy(&_aircraft_vehicle_info, &_orig_aircraft_vehicle_info, sizeof(_orig_aircraft_vehicle_info));
51
memcpy(&_road_vehicle_info, &_orig_road_vehicle_info, sizeof(_orig_road_vehicle_info));
53
/* Add type to engines */
55
do e->type = VEH_TRAIN; while (++e < &_engines[ROAD_ENGINES_INDEX]);
56
do e->type = VEH_ROAD; while (++e < &_engines[SHIP_ENGINES_INDEX]);
57
do e->type = VEH_SHIP; while (++e < &_engines[AIRCRAFT_ENGINES_INDEX]);
58
do e->type = VEH_AIRCRAFT; while (++e < &_engines[TOTAL_NUM_ENGINES]);
60
/* Set up default engine names */
61
for (EngineID engine = 0; engine < TOTAL_NUM_ENGINES; engine++) {
62
EngineInfo *ei = &_engine_info[engine];
63
ei->string_id = STR_8000_KIRBY_PAUL_TANK_STEAM + engine;
395
_Engine_pool.CleanPool();
396
_Engine_pool.AddBlockToPool();
398
assert(_engine_mngr.Length() >= _engine_mngr.NUM_DEFAULT_ENGINES);
399
const EngineIDMapping *end = _engine_mngr.End();
401
for (const EngineIDMapping *eid = _engine_mngr.Begin(); eid != end; eid++, index++) {
402
const Engine *e = new Engine(eid->type, eid->internal_id);
403
assert(e->index == index);
68
408
void ShowEnginePreviewWindow(EngineID engine);
70
void DeleteCustomEngineNames()
78
_vehicle_design_names &= ~1;
81
void LoadCustomEngineNames()
84
DEBUG(misc, 1, "LoadCustomEngineNames: not done");
410
/* Determine if an engine type is a wagon (and not a loco) */
411
static bool IsWagon(EngineID index)
413
const Engine *e = GetEngine(index);
414
return e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON;
87
417
static void CalcEngineReliability(Engine *e)
121
451
InvalidateWindowClasses(WC_REPLACE_VEHICLE);
454
void SetYearEngineAgingStops()
456
/* Determine last engine aging year, default to 2050 as previously. */
457
_year_engine_aging_stops = 2050;
461
const EngineInfo *ei = &e->info;
463
/* Exclude certain engines */
464
if (!HasBit(ei->climates, _settings_game.game_creation.landscape)) continue;
465
if (e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON) continue;
467
/* Base year ending date on half the model life */
469
ConvertDateToYMD(ei->base_intro + (ei->lifelength * DAYS_IN_LEAP_YEAR) / 2, &ymd);
471
_year_engine_aging_stops = max(_year_engine_aging_stops, ymd.year);
475
void StartupOneEngine(Engine *e, Date aging_date)
477
const EngineInfo *ei = &e->info;
482
e->company_avail = 0;
484
/* The magic value of 729 days below comes from the NewGRF spec. If the
485
* base intro date is before 1922 then the random number of days is not
488
e->intro_date = ei->base_intro <= ConvertYMDToDate(1922, 0, 1) ? ei->base_intro : (Date)GB(r, 0, 9) + ei->base_intro;
489
if (e->intro_date <= _date) {
490
e->age = (aging_date - e->intro_date) >> 5;
491
e->company_avail = (CompanyMask)-1;
492
e->flags |= ENGINE_AVAILABLE;
495
e->reliability_start = GB(r, 16, 14) + 0x7AE0;
497
e->reliability_max = GB(r, 0, 14) + 0xBFFF;
498
e->reliability_final = GB(r, 16, 14) + 0x3FFF;
501
e->duration_phase_1 = GB(r, 0, 5) + 7;
502
e->duration_phase_2 = GB(r, 5, 4) + ei->base_life * 12 - 96;
503
e->duration_phase_3 = GB(r, 9, 7) + 120;
505
e->reliability_spd_dec = ei->decay_speed << 2;
507
CalcEngineReliability(e);
509
e->lifelength = ei->lifelength + _settings_game.vehicle.extend_vehicle_life;
511
/* prevent certain engines from ever appearing. */
512
if (!HasBit(ei->climates, _settings_game.game_creation.landscape)) {
513
e->flags |= ENGINE_AVAILABLE;
514
e->company_avail = 0;
124
518
void StartupEngines()
127
const EngineInfo *ei;
128
521
/* Aging of vehicles stops, so account for that when starting late */
129
const Date aging_date = min(_date, ConvertYMDToDate(YEAR_ENGINE_AGING_STOPS, 0, 1));
131
for (e = _engines, ei = _engine_info; e != endof(_engines); e++, ei++) {
138
/* The magic value of 729 days below comes from the NewGRF spec. If the
139
* base intro date is before 1922 then the random number of days is not
142
e->intro_date = ei->base_intro <= ConvertYMDToDate(1922, 0, 1) ? ei->base_intro : (Date)GB(r, 0, 9) + ei->base_intro;
143
if (e->intro_date <= _date) {
144
e->age = (aging_date - e->intro_date) >> 5;
145
e->player_avail = (byte)-1;
146
e->flags |= ENGINE_AVAILABLE;
149
e->reliability_start = GB(r, 16, 14) + 0x7AE0;
151
e->reliability_max = GB(r, 0, 14) + 0xBFFF;
152
e->reliability_final = GB(r, 16, 14) + 0x3FFF;
155
e->duration_phase_1 = GB(r, 0, 5) + 7;
156
e->duration_phase_2 = GB(r, 5, 4) + ei->base_life * 12 - 96;
157
e->duration_phase_3 = GB(r, 9, 7) + 120;
159
e->reliability_spd_dec = (ei->unk2&0x7F) << 2;
161
/* my invented flag for something that is a wagon */
162
if (ei->unk2 & 0x80) {
165
CalcEngineReliability(e);
168
e->lifelength = ei->lifelength + _patches.extend_vehicle_life;
170
/* prevent certain engines from ever appearing. */
171
if (!HasBit(ei->climates, _opt.landscape)) {
172
e->flags |= ENGINE_AVAILABLE;
522
const Date aging_date = min(_date, ConvertYMDToDate(_year_engine_aging_stops, 0, 1));
525
StartupOneEngine(e, aging_date);
177
528
/* Update the bitmasks for the vehicle lists */
180
p->avail_railtypes = GetPlayerRailtypes(p->index);
181
p->avail_roadtypes = GetPlayerRoadtypes(p->index);
530
FOR_ALL_COMPANIES(c) {
531
c->avail_railtypes = GetCompanyRailtypes(c->index);
532
c->avail_roadtypes = GetCompanyRoadtypes(c->index);
185
static void AcceptEnginePreview(EngineID eid, PlayerID player)
536
static void AcceptEnginePreview(EngineID eid, CompanyID company)
187
538
Engine *e = GetEngine(eid);
188
Player *p = GetPlayer(player);
539
Company *c = GetCompany(company);
190
SetBit(e->player_avail, player);
541
SetBit(e->company_avail, company);
191
542
if (e->type == VEH_TRAIN) {
192
543
const RailVehicleInfo *rvi = RailVehInfo(eid);
194
545
assert(rvi->railtype < RAILTYPE_END);
195
SetBit(p->avail_railtypes, rvi->railtype);
546
SetBit(c->avail_railtypes, rvi->railtype);
196
547
} else if (e->type == VEH_ROAD) {
197
SetBit(p->avail_roadtypes, HasBit(EngInfo(eid)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD);
548
SetBit(c->avail_roadtypes, HasBit(EngInfo(eid)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD);
200
e->preview_player_rank = 0xFF;
201
if (player == _local_player) {
551
e->preview_company_rank = 0xFF;
552
if (company == _local_company) {
202
553
AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type);
206
static PlayerID GetBestPlayer(uint8 pp)
557
static CompanyID GetBestCompany(uint8 pp)
210
PlayerID best_player;
561
CompanyID best_company;
562
CompanyMask mask = 0;
215
best_player = PLAYER_SPECTATOR;
217
if (p->is_active && p->block_preview == 0 && !HasBit(mask, p->index) &&
218
p->old_economy[0].performance_history > best_hist) {
219
best_hist = p->old_economy[0].performance_history;
220
best_player = p->index;
566
best_company = INVALID_COMPANY;
567
FOR_ALL_COMPANIES(c) {
568
if (c->block_preview == 0 && !HasBit(mask, c->index) &&
569
c->old_economy[0].performance_history > best_hist) {
570
best_hist = c->old_economy[0].performance_history;
571
best_company = c->index;
224
if (best_player == PLAYER_SPECTATOR) return PLAYER_SPECTATOR;
575
if (best_company == INVALID_COMPANY) return INVALID_COMPANY;
226
SetBit(mask, best_player);
577
SetBit(mask, best_company);
227
578
} while (--pp != 0);
232
583
void EnginesDailyLoop()
236
if (_cur_year >= YEAR_ENGINE_AGING_STOPS) return;
238
for (i = 0; i != lengthof(_engines); i++) {
239
Engine *e = &_engines[i];
585
if (_cur_year >= _year_engine_aging_stops) return;
589
EngineID i = e->index;
241
590
if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) {
242
591
if (e->flags & ENGINE_OFFER_WINDOW_OPEN) {
243
if (e->preview_player_rank != 0xFF && !--e->preview_wait) {
592
if (e->preview_company_rank != 0xFF && !--e->preview_wait) {
244
593
e->flags &= ~ENGINE_OFFER_WINDOW_OPEN;
245
594
DeleteWindowById(WC_ENGINE_PREVIEW, i);
246
e->preview_player_rank++;
595
e->preview_company_rank++;
248
} else if (e->preview_player_rank != 0xFF) {
249
PlayerID best_player = GetBestPlayer(e->preview_player_rank);
597
} else if (e->preview_company_rank != 0xFF) {
598
CompanyID best_company = GetBestCompany(e->preview_company_rank);
251
if (best_player == PLAYER_SPECTATOR) {
252
e->preview_player_rank = 0xFF;
600
if (best_company == INVALID_COMPANY) {
601
e->preview_company_rank = 0xFF;
256
if (!IsHumanPlayer(best_player)) {
257
/* XXX - TTDBUG: TTD has a bug here ???? */
258
AcceptEnginePreview(i, best_player);
260
e->flags |= ENGINE_OFFER_WINDOW_OPEN;
261
e->preview_wait = 20;
262
if (IsInteractivePlayer(best_player)) ShowEnginePreviewWindow(i);
605
e->flags |= ENGINE_OFFER_WINDOW_OPEN;
606
e->preview_wait = 20;
607
AI::NewEvent(best_company, new AIEventEnginePreview(i));
608
if (IsInteractiveCompany(best_company)) ShowEnginePreviewWindow(i);
269
/** Accept an engine prototype. XXX - it is possible that the top-player
614
/** Accept an engine prototype. XXX - it is possible that the top-company
270
615
* changes while you are waiting to accept the offer? Then it becomes invalid
271
616
* @param tile unused
272
617
* @param flags operation to perfom
273
618
* @param p1 engine-prototype offered
274
619
* @param p2 unused
276
CommandCost CmdWantEnginePreview(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
621
CommandCost CmdWantEnginePreview(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
280
625
if (!IsEngineIndex(p1)) return CMD_ERROR;
281
626
e = GetEngine(p1);
282
if (GetBestPlayer(e->preview_player_rank) != _current_player) return CMD_ERROR;
627
if (GetBestCompany(e->preview_company_rank) != _current_company) return CMD_ERROR;
284
if (flags & DC_EXEC) AcceptEnginePreview(p1, _current_player);
629
if (flags & DC_EXEC) AcceptEnginePreview(p1, _current_company);
286
631
return CommandCost();
289
/* Determine if an engine type is a wagon (and not a loco) */
290
static bool IsWagon(EngineID index)
292
return index < NUM_TRAIN_ENGINES && RailVehInfo(index)->railveh_type == RAILVEH_WAGON;
634
StringID GetEngineCategoryName(EngineID engine);
295
636
static void NewVehicleAvailable(Engine *e)
299
EngineID index = e - _engines;
640
EngineID index = e->index;
301
/* In case the player didn't build the vehicle during the intro period,
302
* prevent that player from getting future intro periods for a while. */
642
/* In case the company didn't build the vehicle during the intro period,
643
* prevent that company from getting future intro periods for a while. */
303
644
if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) {
305
uint block_preview = p->block_preview;
645
FOR_ALL_COMPANIES(c) {
646
uint block_preview = c->block_preview;
307
if (!HasBit(e->player_avail, p->index)) continue;
648
if (!HasBit(e->company_avail, c->index)) continue;
309
650
/* We assume the user did NOT build it.. prove me wrong ;) */
310
p->block_preview = 20;
651
c->block_preview = 20;
312
653
FOR_ALL_VEHICLES(v) {
313
654
if (v->type == VEH_TRAIN || v->type == VEH_ROAD || v->type == VEH_SHIP ||
314
655
(v->type == VEH_AIRCRAFT && IsNormalAircraft(v))) {
315
if (v->owner == p->index && v->engine_type == index) {
656
if (v->owner == c->index && v->engine_type == index) {
316
657
/* The user did prove me wrong, so restore old value */
317
p->block_preview = block_preview;
658
c->block_preview = block_preview;
428
778
if (e->type != type) return false;
430
780
/* check if it's available */
431
if (!HasBit(e->player_avail, player)) return false;
781
if (!HasBit(e->company_avail, company)) return false;
433
783
if (type == VEH_TRAIN) {
434
/* Check if the rail type is available to this player */
435
const Player *p = GetPlayer(player);
436
if (!HasBit(p->avail_railtypes, RailVehInfo(engine)->railtype)) return false;
784
/* Check if the rail type is available to this company */
785
const Company *c = GetCompany(company);
786
if (!HasBit(c->avail_railtypes, RailVehInfo(engine)->railtype)) return false;
442
/** Get the default cargo type for a certain engine type
443
* @param engine The ID to get the cargo for
444
* @return The cargo type. CT_INVALID means no cargo capacity
793
* Check if an engine is refittable.
794
* Note: Likely you want to use IsArticulatedVehicleRefittable().
795
* @param engine index of the engine to check.
796
* @return true if the engine is refittable.
446
CargoID GetEngineCargoType(EngineID engine)
448
assert(IsEngineIndex(engine));
450
switch (GetEngine(engine)->type) {
452
if (RailVehInfo(engine)->capacity == 0) return CT_INVALID;
453
return RailVehInfo(engine)->cargo_type;
456
if (RoadVehInfo(engine)->capacity == 0) return CT_INVALID;
457
return RoadVehInfo(engine)->cargo_type;
460
if (ShipVehInfo(engine)->capacity == 0) return CT_INVALID;
461
return ShipVehInfo(engine)->cargo_type;
464
/* all aircraft starts as passenger planes with cargo capacity */
465
return CT_PASSENGERS;
467
default: NOT_REACHED(); return CT_INVALID;
471
/************************************************************************
472
* Engine Replacement stuff
473
************************************************************************/
475
DEFINE_OLD_POOL_GENERIC(EngineRenew, EngineRenew)
478
* Retrieves the EngineRenew that specifies the replacement of the given
479
* engine type from the given renewlist */
480
static EngineRenew *GetEngineReplacement(EngineRenewList erl, EngineID engine, GroupID group)
482
EngineRenew *er = (EngineRenew *)erl;
485
if (er->from == engine && er->group_id == group) return er;
491
void RemoveAllEngineReplacement(EngineRenewList *erl)
493
EngineRenew *er = (EngineRenew *)(*erl);
501
*erl = NULL; // Empty list
504
EngineID EngineReplacement(EngineRenewList erl, EngineID engine, GroupID group)
506
const EngineRenew *er = GetEngineReplacement(erl, engine, group);
507
if (er == NULL && (group == DEFAULT_GROUP || (IsValidGroupID(group) && !GetGroup(group)->replace_protection))) {
508
/* We didn't find anything useful in the vehicle's own group so we will try ALL_GROUP */
509
er = GetEngineReplacement(erl, engine, ALL_GROUP);
511
return er == NULL ? INVALID_ENGINE : er->to;
514
CommandCost AddEngineReplacement(EngineRenewList *erl, EngineID old_engine, EngineID new_engine, GroupID group, uint32 flags)
518
/* Check if the old vehicle is already in the list */
519
er = GetEngineReplacement(*erl, old_engine, group);
521
if (flags & DC_EXEC) er->to = new_engine;
522
return CommandCost();
525
if (!EngineRenew::CanAllocateItem()) return CMD_ERROR;
527
if (flags & DC_EXEC) {
528
er = new EngineRenew(old_engine, new_engine);
529
er->group_id = group;
531
/* Insert before the first element */
532
er->next = (EngineRenew *)(*erl);
533
*erl = (EngineRenewList)er;
536
return CommandCost();
539
CommandCost RemoveEngineReplacement(EngineRenewList *erl, EngineID engine, GroupID group, uint32 flags)
541
EngineRenew *er = (EngineRenew *)(*erl);
542
EngineRenew *prev = NULL;
546
if (er->from == engine && er->group_id == group) {
547
if (flags & DC_EXEC) {
548
if (prev == NULL) { // First element
549
/* The second becomes the new first element */
550
*erl = (EngineRenewList)er->next;
552
/* Cut this element out */
553
prev->next = er->next;
557
return CommandCost();
566
static const SaveLoad _engine_renew_desc[] = {
567
SLE_VAR(EngineRenew, from, SLE_UINT16),
568
SLE_VAR(EngineRenew, to, SLE_UINT16),
570
SLE_REF(EngineRenew, next, REF_ENGINE_RENEWS),
571
SLE_CONDVAR(EngineRenew, group_id, SLE_UINT16, 60, SL_MAX_VERSION),
575
static void Save_ERNW()
579
FOR_ALL_ENGINE_RENEWS(er) {
580
SlSetArrayIndex(er->index);
581
SlObject(er, _engine_renew_desc);
585
static void Load_ERNW()
589
while ((index = SlIterateArray()) != -1) {
590
EngineRenew *er = new (index) EngineRenew();
591
SlObject(er, _engine_renew_desc);
593
/* Advanced vehicle lists, ungrouped vehicles got added */
594
if (CheckSavegameVersion(60)) {
595
er->group_id = ALL_GROUP;
596
} else if (CheckSavegameVersion(71)) {
597
if (er->group_id == DEFAULT_GROUP) er->group_id = ALL_GROUP;
602
static const SaveLoad _engine_desc[] = {
603
SLE_CONDVAR(Engine, intro_date, SLE_FILE_U16 | SLE_VAR_I32, 0, 30),
604
SLE_CONDVAR(Engine, intro_date, SLE_INT32, 31, SL_MAX_VERSION),
605
SLE_CONDVAR(Engine, age, SLE_FILE_U16 | SLE_VAR_I32, 0, 30),
606
SLE_CONDVAR(Engine, age, SLE_INT32, 31, SL_MAX_VERSION),
607
SLE_VAR(Engine, reliability, SLE_UINT16),
608
SLE_VAR(Engine, reliability_spd_dec, SLE_UINT16),
609
SLE_VAR(Engine, reliability_start, SLE_UINT16),
610
SLE_VAR(Engine, reliability_max, SLE_UINT16),
611
SLE_VAR(Engine, reliability_final, SLE_UINT16),
612
SLE_VAR(Engine, duration_phase_1, SLE_UINT16),
613
SLE_VAR(Engine, duration_phase_2, SLE_UINT16),
614
SLE_VAR(Engine, duration_phase_3, SLE_UINT16),
616
SLE_VAR(Engine, lifelength, SLE_UINT8),
617
SLE_VAR(Engine, flags, SLE_UINT8),
618
SLE_VAR(Engine, preview_player_rank, SLE_UINT8),
619
SLE_VAR(Engine, preview_wait, SLE_UINT8),
620
SLE_CONDNULL(1, 0, 44),
621
SLE_VAR(Engine, player_avail, SLE_UINT8),
622
SLE_CONDSTR(Engine, name, SLE_STR, 0, 84, SL_MAX_VERSION),
624
/* reserve extra space in savegame here. (currently 16 bytes) */
625
SLE_CONDNULL(16, 2, SL_MAX_VERSION),
630
static void Save_ENGN()
634
for (i = 0; i != lengthof(_engines); i++) {
636
SlObject(&_engines[i], _engine_desc);
640
static void Load_ENGN()
643
while ((index = SlIterateArray()) != -1) {
644
SlObject(GetEngine(index), _engine_desc);
648
static void Load_ENGS()
650
StringID names[TOTAL_NUM_ENGINES];
652
SlArray(names, lengthof(names), SLE_STRINGID);
654
for (EngineID engine = 0; engine < lengthof(names); engine++) {
655
Engine *e = GetEngine(engine);
656
e->name = CopyFromOldName(names[engine]);
660
extern const ChunkHandler _engine_chunk_handlers[] = {
661
{ 'ENGN', Save_ENGN, Load_ENGN, CH_ARRAY },
662
{ 'ENGS', NULL, Load_ENGS, CH_RIFF },
663
{ 'ERNW', Save_ERNW, Load_ERNW, CH_ARRAY | CH_LAST},
666
void InitializeEngines()
668
/* Clean the engine renew pool and create 1 block in it */
669
_EngineRenew_pool.CleanPool();
670
_EngineRenew_pool.AddBlockToPool();
798
bool IsEngineRefittable(EngineID engine)
800
/* check if it's an engine that is in the engine array */
801
if (!IsEngineIndex(engine)) return false;
803
const Engine *e = GetEngine(engine);
805
if (e->type == VEH_SHIP && !e->u.ship.refittable) return false;
807
if (!e->CanCarryCargo()) return false;
809
const EngineInfo *ei = &e->info;
810
if (ei->refit_mask == 0) return false;
812
/* Are there suffixes?
813
* Note: This does not mean the suffixes are actually available for every consist at any time. */
814
if (HasBit(ei->callbackmask, CBM_VEHICLE_CARGO_SUFFIX)) return true;
816
/* Is there any cargo except the default cargo? */
817
CargoID default_cargo = e->GetDefaultCargoType();
818
return default_cargo != CT_INVALID && ei->refit_mask != 1U << default_cargo;