~ubuntu-branches/debian/squeeze/openttd/squeeze

« back to all changes in this revision

Viewing changes to src/engine.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jordi Mallach, Matthijs Kooijman, Jordi Mallach
  • Date: 2009-04-15 18:22:10 UTC
  • mfrom: (1.1.6 upstream) (2.1.3 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090415182210-22ktb8kdbp2tf3bm
[ Matthijs Kooijman ]
* New upstream release.
* Remove Debian specific desktop file, upstream provides one now. 
* Add debian/watch file.

[ Jordi Mallach ]
* Bump Standards-Version to 3.8.1, with no changes required.
* Move to debhelper compat 7. Bump Build-Depends accordingly.
* Use dh_prep.
* Add "set -e" to config script.
* Remove a few extra doc files that get installed by upstream Makefile.
* Add more complete copyright information.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: engine.cpp 14268 2008-09-07 22:04:39Z rubidium $ */
 
1
/* $Id: engine.cpp 15765 2009-03-18 19:50:34Z rubidium $ */
2
2
 
3
 
/** @file engine.cpp */
 
3
/** @file engine.cpp Base for all engine handling. */
4
4
 
5
5
#include "stdafx.h"
6
 
#include "openttd.h"
7
6
#include "debug.h"
8
 
#include "engine.h"
9
 
#include "player_base.h"
10
 
#include "player_func.h"
 
7
#include "company_func.h"
11
8
#include "command_func.h"
12
 
#include "news.h"
13
 
#include "saveload.h"
 
9
#include "news_func.h"
14
10
#include "variables.h"
15
 
#include "train.h"
16
11
#include "aircraft.h"
17
 
#include "newgrf_cargo.h"
 
12
#include "newgrf_engine.h"
18
13
#include "group.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"
 
22
#include "ai/ai.hpp"
 
23
#include "vehicle_func.h"
27
24
#include "settings_type.h"
28
25
 
29
26
#include "table/strings.h"
30
27
#include "table/engines.h"
31
28
 
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];
38
 
 
39
 
enum {
40
 
        YEAR_ENGINE_AGING_STOPS = 2050,
41
 
};
42
 
 
 
29
DEFINE_OLD_POOL_GENERIC(Engine, Engine)
 
30
 
 
31
EngineOverrideManager _engine_mngr;
 
32
 
 
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;
 
36
 
 
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),
 
43
};
 
44
 
 
45
/** Offset of the first engine of each vehicle type in original engine data */
 
46
const uint8 _engine_offsets[4] = {
 
47
        0,
 
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),
 
51
};
 
52
 
 
53
const uint EngineOverrideManager::NUM_DEFAULT_ENGINES = _engine_counts[VEH_TRAIN] + _engine_counts[VEH_ROAD] + _engine_counts[VEH_SHIP] + _engine_counts[VEH_AIRCRAFT];
 
54
 
 
55
Engine::Engine() :
 
56
        name(NULL),
 
57
        overrides_count(0),
 
58
        overrides(NULL)
 
59
{
 
60
}
 
61
 
 
62
Engine::Engine(VehicleType type, EngineID base)
 
63
{
 
64
        this->type = type;
 
65
        this->internal_id = base;
 
66
        this->list_position = base;
 
67
 
 
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;
 
74
                return;
 
75
        }
 
76
 
 
77
        /* Copy the original engine info for this slot */
 
78
        this->info = _orig_engine_info[_engine_offsets[type] + base];
 
79
 
 
80
        /* Copy the original engine data for this slot */
 
81
        switch (type) {
 
82
                default: NOT_REACHED();
 
83
 
 
84
                case VEH_TRAIN:
 
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;
 
88
 
 
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;
 
91
 
 
92
                        break;
 
93
 
 
94
                case VEH_ROAD:
 
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;
 
98
                        break;
 
99
 
 
100
                case VEH_SHIP:
 
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;
 
104
                        break;
 
105
 
 
106
                case VEH_AIRCRAFT:
 
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;
 
110
                        break;
 
111
        }
 
112
}
 
113
 
 
114
Engine::~Engine()
 
115
{
 
116
        UnloadWagonOverrides(this);
 
117
        free(this->name);
 
118
}
 
119
 
 
120
/**
 
121
 * Determines the default cargo type of an engine.
 
122
 *
 
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..
 
125
 *
 
126
 * Vehicles with CT_INVALID as default cargo are usally not available, but it can appear as default cargo of articulated parts.
 
127
 *
 
128
 * @return The default cargo type.
 
129
 * @see CanCarryCargo
 
130
 */
 
131
CargoID Engine::GetDefaultCargoType() const
 
132
{
 
133
        switch (this->type) {
 
134
                case VEH_TRAIN:
 
135
                        return this->u.rail.cargo_type;
 
136
 
 
137
                case VEH_ROAD:
 
138
                        return this->u.road.cargo_type;
 
139
 
 
140
                case VEH_SHIP:
 
141
                        return this->u.ship.cargo_type;
 
142
 
 
143
                case VEH_AIRCRAFT:
 
144
                        return FindFirstRefittableCargo(this->index);
 
145
 
 
146
                default: NOT_REACHED();
 
147
        }
 
148
}
 
149
 
 
150
/**
 
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.
 
154
 */
 
155
bool Engine::CanCarryCargo() const
 
156
{
 
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.
 
161
         */
 
162
        switch (this->type) {
 
163
                case VEH_TRAIN:
 
164
                        if (this->u.rail.capacity == 0) return false;
 
165
                        break;
 
166
 
 
167
                case VEH_ROAD:
 
168
                        if (this->u.road.capacity == 0) return false;
 
169
                        break;
 
170
 
 
171
                case VEH_SHIP:
 
172
                case VEH_AIRCRAFT:
 
173
                        break;
 
174
 
 
175
                default: NOT_REACHED();
 
176
        }
 
177
        return this->GetDefaultCargoType() != CT_INVALID;
 
178
}
 
179
 
 
180
/**
 
181
 * Determines the default cargo capacity of an engine for display purposes.
 
182
 *
 
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
 
186
 *
 
187
 * @return The default capacity
 
188
 * @see GetDefaultCargoType
 
189
 */
 
190
uint Engine::GetDisplayDefaultCapacity() const
 
191
{
 
192
        if (!this->CanCarryCargo()) return 0;
 
193
        switch (type) {
 
194
                case VEH_TRAIN:
 
195
                        return GetEngineProperty(this->index, 0x14, this->u.rail.capacity) + (this->u.rail.railveh_type == RAILVEH_MULTIHEAD ? this->u.rail.capacity : 0);
 
196
 
 
197
                case VEH_ROAD:
 
198
                        return GetEngineProperty(this->index, 0x0F, this->u.road.capacity);
 
199
 
 
200
                case VEH_SHIP:
 
201
                        return GetEngineProperty(this->index, 0x0D, this->u.ship.capacity);
 
202
 
 
203
                case VEH_AIRCRAFT:
 
204
                        return AircraftDefaultCargoCapacity(this->GetDefaultCargoType(), &this->u.air);
 
205
 
 
206
                default: NOT_REACHED();
 
207
        }
 
208
}
 
209
 
 
210
Money Engine::GetRunningCost() const
 
211
{
 
212
        switch (this->type) {
 
213
                case VEH_ROAD:
 
214
                        return this->u.road.running_cost * GetPriceByIndex(this->u.road.running_cost_class) >> 8;
 
215
 
 
216
                case VEH_TRAIN:
 
217
                        return GetEngineProperty(this->index, 0x0D, this->u.rail.running_cost) * GetPriceByIndex(this->u.rail.running_cost_class) >> 8;
 
218
 
 
219
                case VEH_SHIP:
 
220
                        return GetEngineProperty(this->index, 0x0F, this->u.ship.running_cost) * _price.ship_running >> 8;
 
221
 
 
222
                case VEH_AIRCRAFT:
 
223
                        return GetEngineProperty(this->index, 0x0E, this->u.air.running_cost) * _price.aircraft_running >> 8;
 
224
 
 
225
                default: NOT_REACHED();
 
226
        }
 
227
}
 
228
 
 
229
Money Engine::GetCost() const
 
230
{
 
231
        switch (this->type) {
 
232
                case VEH_ROAD:
 
233
                        return GetEngineProperty(this->index, 0x11, this->u.road.cost_factor) * (_price.roadveh_base >> 3) >> 5;
 
234
 
 
235
                case VEH_TRAIN:
 
236
                        if (this->u.rail.railveh_type == RAILVEH_WAGON) {
 
237
                                return (GetEngineProperty(this->index, 0x17, this->u.rail.cost_factor) * _price.build_railwagon) >> 8;
 
238
                        } else {
 
239
                                return GetEngineProperty(this->index, 0x17, this->u.rail.cost_factor) * (_price.build_railvehicle >> 3) >> 5;
 
240
                        }
 
241
                case VEH_SHIP:
 
242
                        return GetEngineProperty(this->index, 0x0A, this->u.ship.cost_factor) * (_price.ship_base >> 3) >> 5;
 
243
 
 
244
                case VEH_AIRCRAFT:
 
245
                        return GetEngineProperty(this->index, 0x0B, this->u.air.cost_factor) * (_price.aircraft_base >> 3) >> 5;
 
246
 
 
247
                default: NOT_REACHED();
 
248
        }
 
249
}
 
250
 
 
251
/**
 
252
 * Returns max speed for display purposes
 
253
 * @return max speed in km-ish/h
 
254
 */
 
255
uint Engine::GetDisplayMaxSpeed() const
 
256
{
 
257
        switch (this->type) {
 
258
                case VEH_TRAIN:
 
259
                        return GetEngineProperty(this->index, 0x09, this->u.rail.max_speed);
 
260
 
 
261
                case VEH_ROAD:
 
262
                        return this->u.road.max_speed / 2;
 
263
 
 
264
                case VEH_SHIP:
 
265
                        return GetEngineProperty(this->index, 0x0B, this->u.ship.max_speed) / 2;
 
266
 
 
267
                case VEH_AIRCRAFT:
 
268
                        return this->u.air.max_speed;
 
269
 
 
270
                default: NOT_REACHED();
 
271
        }
 
272
}
 
273
 
 
274
uint Engine::GetPower() const
 
275
{
 
276
        /* Currently only trains have 'power' */
 
277
        switch (this->type) {
 
278
                case VEH_TRAIN:
 
279
                        return GetEngineProperty(this->index, 0x0B, this->u.rail.power);
 
280
 
 
281
                default: NOT_REACHED();
 
282
        }
 
283
}
 
284
 
 
285
/**
 
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
 
289
 */
 
290
uint Engine::GetDisplayWeight() const
 
291
{
 
292
        /* Currently only trains have 'weight' */
 
293
        switch (this->type) {
 
294
                case VEH_TRAIN:
 
295
                        return GetEngineProperty(this->index, 0x16, this->u.rail.weight) << (this->u.rail.railveh_type == RAILVEH_MULTIHEAD ? 1 : 0);
 
296
 
 
297
                default: NOT_REACHED();
 
298
        }
 
299
}
 
300
 
 
301
/**
 
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
 
305
 */
 
306
uint Engine::GetDisplayMaxTractiveEffort() const
 
307
{
 
308
        /* Currently only trains have 'tractive effort' */
 
309
        switch (this->type) {
 
310
                case VEH_TRAIN:
 
311
                        return (10 * this->GetDisplayWeight() * GetEngineProperty(this->index, 0x1F, this->u.rail.tractive_effort)) / 256;
 
312
 
 
313
                default: NOT_REACHED();
 
314
        }
 
315
}
 
316
 
 
317
/**
 
318
 * Initializes the EngineOverrideManager with the default engines.
 
319
 */
 
320
void EngineOverrideManager::ResetToDefaultMapping()
 
321
{
 
322
        this->Clear();
 
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();
 
326
                        eid->type            = type;
 
327
                        eid->grfid           = INVALID_GRFID;
 
328
                        eid->internal_id     = internal_id;
 
329
                        eid->substitute_id   = internal_id;
 
330
                }
 
331
        }
 
332
}
 
333
 
 
334
/**
 
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.
 
342
 */
 
343
EngineID EngineOverrideManager::GetID(VehicleType type, uint16 grf_local_id, uint32 grfid)
 
344
{
 
345
        const EngineIDMapping *end = this->End();
 
346
        EngineID index = 0;
 
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) {
 
349
                        return index;
 
350
                }
 
351
        }
 
352
        return INVALID_ENGINE;
 
353
}
 
354
 
 
355
/** Sets cached values in Company::num_vehicles and Group::num_vehicles
 
356
 */
 
357
void SetCachedEngineCounts()
 
358
{
 
359
        uint engines = GetEnginePoolSize();
 
360
 
 
361
        /* Set up the engine count for all companies */
 
362
        Company *c;
 
363
        FOR_ALL_COMPANIES(c) {
 
364
                free(c->num_engines);
 
365
                c->num_engines = CallocT<EngineID>(engines);
 
366
        }
 
367
 
 
368
        /* Recalculate */
 
369
        Group *g;
 
370
        FOR_ALL_GROUPS(g) {
 
371
                free(g->num_engines);
 
372
                g->num_engines = CallocT<EngineID>(engines);
 
373
        }
 
374
 
 
375
        const Vehicle *v;
 
376
        FOR_ALL_VEHICLES(v) {
 
377
                if (!IsEngineCountable(v)) continue;
 
378
 
 
379
                assert(v->engine_type < engines);
 
380
 
 
381
                GetCompany(v->owner)->num_engines[v->engine_type]++;
 
382
 
 
383
                if (v->group_id == DEFAULT_GROUP) continue;
 
384
 
 
385
                g = GetGroup(v->group_id);
 
386
                assert(v->type == g->vehicle_type);
 
387
                assert(v->owner == g->owner);
 
388
 
 
389
                g->num_engines[v->engine_type]++;
 
390
        }
 
391
}
43
392
 
44
393
void SetupEngines()
45
394
{
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));
52
 
 
53
 
        /* Add type to engines */
54
 
        Engine* e = _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]);
59
 
 
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();
 
397
 
 
398
        assert(_engine_mngr.Length() >= _engine_mngr.NUM_DEFAULT_ENGINES);
 
399
        const EngineIDMapping *end = _engine_mngr.End();
 
400
        uint index = 0;
 
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);
64
404
        }
65
405
}
66
406
 
67
407
 
68
408
void ShowEnginePreviewWindow(EngineID engine);
69
409
 
70
 
void DeleteCustomEngineNames()
71
 
{
72
 
        Engine *e;
73
 
        FOR_ALL_ENGINES(e) {
74
 
                free(e->name);
75
 
                e->name = NULL;
76
 
        }
77
 
 
78
 
        _vehicle_design_names &= ~1;
79
 
}
80
 
 
81
 
void LoadCustomEngineNames()
82
 
{
83
 
        /* XXX: not done */
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)
 
412
{
 
413
        const Engine *e = GetEngine(index);
 
414
        return e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON;
85
415
}
86
416
 
87
417
static void CalcEngineReliability(Engine *e)
89
419
        uint age = e->age;
90
420
 
91
421
        /* Check for early retirement */
92
 
        if (e->player_avail != 0 && !_patches.never_expire_vehicles) {
93
 
                int retire_early = EngInfo(e - _engines)->retire_early;
 
422
        if (e->company_avail != 0 && !_settings_game.vehicle.never_expire_vehicles && e->info.base_life != 0xFF) {
 
423
                int retire_early = e->info.retire_early;
94
424
                uint retire_early_max_age = max(0, e->duration_phase_1 + e->duration_phase_2 - retire_early * 12);
95
425
                if (retire_early != 0 && age >= retire_early_max_age) {
96
426
                        /* Early retirement is enabled and we're past the date... */
97
 
                        e->player_avail = 0;
 
427
                        e->company_avail = 0;
98
428
                        AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type);
99
429
                }
100
430
        }
102
432
        if (age < e->duration_phase_1) {
103
433
                uint start = e->reliability_start;
104
434
                e->reliability = age * (e->reliability_max - start) / e->duration_phase_1 + start;
105
 
        } else if ((age -= e->duration_phase_1) < e->duration_phase_2 || _patches.never_expire_vehicles) {
 
435
        } else if ((age -= e->duration_phase_1) < e->duration_phase_2 || _settings_game.vehicle.never_expire_vehicles || e->info.base_life == 0xFF) {
106
436
                /* We are at the peak of this engines life. It will have max reliability.
107
437
                 * This is also true if the engines never expire. They will not go bad over time */
108
438
                e->reliability = e->reliability_max;
112
442
        } else {
113
443
                /* time's up for this engine.
114
444
                 * We will now completely retire this design */
115
 
                e->player_avail = 0;
 
445
                e->company_avail = 0;
116
446
                e->reliability = e->reliability_final;
117
447
                /* Kick this engine out of the lists */
118
448
                AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type);
121
451
        InvalidateWindowClasses(WC_REPLACE_VEHICLE);
122
452
}
123
453
 
 
454
void SetYearEngineAgingStops()
 
455
{
 
456
        /* Determine last engine aging year, default to 2050 as previously. */
 
457
        _year_engine_aging_stops = 2050;
 
458
 
 
459
        const Engine *e;
 
460
        FOR_ALL_ENGINES(e) {
 
461
                const EngineInfo *ei = &e->info;
 
462
 
 
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;
 
466
 
 
467
                /* Base year ending date on half the model life */
 
468
                YearMonthDay ymd;
 
469
                ConvertDateToYMD(ei->base_intro + (ei->lifelength * DAYS_IN_LEAP_YEAR) / 2, &ymd);
 
470
 
 
471
                _year_engine_aging_stops = max(_year_engine_aging_stops, ymd.year);
 
472
        }
 
473
}
 
474
 
 
475
void StartupOneEngine(Engine *e, Date aging_date)
 
476
{
 
477
        const EngineInfo *ei = &e->info;
 
478
        uint32 r;
 
479
 
 
480
        e->age = 0;
 
481
        e->flags = 0;
 
482
        e->company_avail = 0;
 
483
 
 
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
 
486
         * added. */
 
487
        r = Random();
 
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;
 
493
        }
 
494
 
 
495
        e->reliability_start = GB(r, 16, 14) + 0x7AE0;
 
496
        r = Random();
 
497
        e->reliability_max   = GB(r,  0, 14) + 0xBFFF;
 
498
        e->reliability_final = GB(r, 16, 14) + 0x3FFF;
 
499
 
 
500
        r = Random();
 
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;
 
504
 
 
505
        e->reliability_spd_dec = ei->decay_speed << 2;
 
506
 
 
507
        CalcEngineReliability(e);
 
508
 
 
509
        e->lifelength = ei->lifelength + _settings_game.vehicle.extend_vehicle_life;
 
510
 
 
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;
 
515
        }
 
516
}
 
517
 
124
518
void StartupEngines()
125
519
{
126
520
        Engine *e;
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));
130
 
 
131
 
        for (e = _engines, ei = _engine_info; e != endof(_engines); e++, ei++) {
132
 
                uint32 r;
133
 
 
134
 
                e->age = 0;
135
 
                e->flags = 0;
136
 
                e->player_avail = 0;
137
 
 
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
140
 
                 * added. */
141
 
                r = Random();
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;
147
 
                }
148
 
 
149
 
                e->reliability_start = GB(r, 16, 14) + 0x7AE0;
150
 
                r = Random();
151
 
                e->reliability_max   = GB(r,  0, 14) + 0xBFFF;
152
 
                e->reliability_final = GB(r, 16, 14) + 0x3FFF;
153
 
 
154
 
                r = Random();
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;
158
 
 
159
 
                e->reliability_spd_dec = (ei->unk2&0x7F) << 2;
160
 
 
161
 
                /* my invented flag for something that is a wagon */
162
 
                if (ei->unk2 & 0x80) {
163
 
                        e->age = 0xFFFF;
164
 
                } else {
165
 
                        CalcEngineReliability(e);
166
 
                }
167
 
 
168
 
                e->lifelength = ei->lifelength + _patches.extend_vehicle_life;
169
 
 
170
 
                /* prevent certain engines from ever appearing. */
171
 
                if (!HasBit(ei->climates, _opt.landscape)) {
172
 
                        e->flags |= ENGINE_AVAILABLE;
173
 
                        e->player_avail = 0;
174
 
                }
 
522
        const Date aging_date = min(_date, ConvertYMDToDate(_year_engine_aging_stops, 0, 1));
 
523
 
 
524
        FOR_ALL_ENGINES(e) {
 
525
                StartupOneEngine(e, aging_date);
175
526
        }
176
527
 
177
528
        /* Update the bitmasks for the vehicle lists */
178
 
        Player *p;
179
 
        FOR_ALL_PLAYERS(p) {
180
 
                p->avail_railtypes = GetPlayerRailtypes(p->index);
181
 
                p->avail_roadtypes = GetPlayerRoadtypes(p->index);
 
529
        Company *c;
 
530
        FOR_ALL_COMPANIES(c) {
 
531
                c->avail_railtypes = GetCompanyRailtypes(c->index);
 
532
                c->avail_roadtypes = GetCompanyRoadtypes(c->index);
182
533
        }
183
534
}
184
535
 
185
 
static void AcceptEnginePreview(EngineID eid, PlayerID player)
 
536
static void AcceptEnginePreview(EngineID eid, CompanyID company)
186
537
{
187
538
        Engine *e = GetEngine(eid);
188
 
        Player *p = GetPlayer(player);
 
539
        Company *c = GetCompany(company);
189
540
 
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);
193
544
 
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);
198
549
        }
199
550
 
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);
203
554
        }
204
555
}
205
556
 
206
 
static PlayerID GetBestPlayer(uint8 pp)
 
557
static CompanyID GetBestCompany(uint8 pp)
207
558
{
208
 
        const Player *p;
 
559
        const Company *c;
209
560
        int32 best_hist;
210
 
        PlayerID best_player;
211
 
        uint mask = 0;
 
561
        CompanyID best_company;
 
562
        CompanyMask mask = 0;
212
563
 
213
564
        do {
214
565
                best_hist = -1;
215
 
                best_player = PLAYER_SPECTATOR;
216
 
                FOR_ALL_PLAYERS(p) {
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;
221
572
                        }
222
573
                }
223
574
 
224
 
                if (best_player == PLAYER_SPECTATOR) return PLAYER_SPECTATOR;
 
575
                if (best_company == INVALID_COMPANY) return INVALID_COMPANY;
225
576
 
226
 
                SetBit(mask, best_player);
 
577
                SetBit(mask, best_company);
227
578
        } while (--pp != 0);
228
579
 
229
 
        return best_player;
 
580
        return best_company;
230
581
}
231
582
 
232
583
void EnginesDailyLoop()
233
584
{
234
 
        EngineID i;
235
 
 
236
 
        if (_cur_year >= YEAR_ENGINE_AGING_STOPS) return;
237
 
 
238
 
        for (i = 0; i != lengthof(_engines); i++) {
239
 
                Engine *e = &_engines[i];
240
 
 
 
585
        if (_cur_year >= _year_engine_aging_stops) return;
 
586
 
 
587
        Engine *e;
 
588
        FOR_ALL_ENGINES(e) {
 
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++;
247
596
                                }
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);
250
599
 
251
 
                                if (best_player == PLAYER_SPECTATOR) {
252
 
                                        e->preview_player_rank = 0xFF;
 
600
                                if (best_company == INVALID_COMPANY) {
 
601
                                        e->preview_company_rank = 0xFF;
253
602
                                        continue;
254
603
                                }
255
604
 
256
 
                                if (!IsHumanPlayer(best_player)) {
257
 
                                        /* XXX - TTDBUG: TTD has a bug here ???? */
258
 
                                        AcceptEnginePreview(i, best_player);
259
 
                                } else {
260
 
                                        e->flags |= ENGINE_OFFER_WINDOW_OPEN;
261
 
                                        e->preview_wait = 20;
262
 
                                        if (IsInteractivePlayer(best_player)) ShowEnginePreviewWindow(i);
263
 
                                }
 
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);
264
609
                        }
265
610
                }
266
611
        }
267
612
}
268
613
 
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
275
620
 */
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)
277
622
{
278
623
        Engine *e;
279
624
 
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;
283
628
 
284
 
        if (flags & DC_EXEC) AcceptEnginePreview(p1, _current_player);
 
629
        if (flags & DC_EXEC) AcceptEnginePreview(p1, _current_company);
285
630
 
286
631
        return CommandCost();
287
632
}
288
633
 
289
 
/* Determine if an engine type is a wagon (and not a loco) */
290
 
static bool IsWagon(EngineID index)
291
 
{
292
 
        return index < NUM_TRAIN_ENGINES && RailVehInfo(index)->railveh_type == RAILVEH_WAGON;
293
 
}
 
634
StringID GetEngineCategoryName(EngineID engine);
294
635
 
295
636
static void NewVehicleAvailable(Engine *e)
296
637
{
297
638
        Vehicle *v;
298
 
        Player *p;
299
 
        EngineID index = e - _engines;
 
639
        Company *c;
 
640
        EngineID index = e->index;
300
641
 
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) {
304
 
                FOR_ALL_PLAYERS(p) {
305
 
                        uint block_preview = p->block_preview;
 
645
                FOR_ALL_COMPANIES(c) {
 
646
                        uint block_preview = c->block_preview;
306
647
 
307
 
                        if (!HasBit(e->player_avail, p->index)) continue;
 
648
                        if (!HasBit(e->company_avail, c->index)) continue;
308
649
 
309
650
                        /* We assume the user did NOT build it.. prove me wrong ;) */
310
 
                        p->block_preview = 20;
 
651
                        c->block_preview = 20;
311
652
 
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;
318
659
                                                break;
319
660
                                        }
320
661
                                }
325
666
        e->flags = (e->flags & ~ENGINE_EXCLUSIVE_PREVIEW) | ENGINE_AVAILABLE;
326
667
        AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type);
327
668
 
328
 
        /* Now available for all players */
329
 
        e->player_avail = (byte)-1;
 
669
        /* Now available for all companies */
 
670
        e->company_avail = (CompanyMask)-1;
330
671
 
331
672
        /* Do not introduce new rail wagons */
332
673
        if (IsWagon(index)) return;
333
674
 
334
675
        if (e->type == VEH_TRAIN) {
335
676
                /* maybe make another rail type available */
336
 
                RailType railtype = RailVehInfo(index)->railtype;
 
677
                RailType railtype = e->u.rail.railtype;
337
678
                assert(railtype < RAILTYPE_END);
338
 
                FOR_ALL_PLAYERS(p) {
339
 
                        if (p->is_active) SetBit(p->avail_railtypes, railtype);
340
 
                }
 
679
                FOR_ALL_COMPANIES(c) SetBit(c->avail_railtypes, railtype);
341
680
        } else if (e->type == VEH_ROAD) {
342
681
                /* maybe make another road type available */
343
 
                FOR_ALL_PLAYERS(p) {
344
 
                        if (p->is_active) SetBit(p->avail_roadtypes, HasBit(EngInfo(index)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD);
345
 
                }
 
682
                FOR_ALL_COMPANIES(c) SetBit(c->avail_roadtypes, HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD);
346
683
        }
347
 
        AddNewsItem(index, NEWS_FLAGS(NM_CALLBACK, 0, NT_NEW_VEHICLES, DNC_VEHICLEAVAIL), 0, 0);
 
684
 
 
685
        AI::BroadcastNewEvent(new AIEventEngineAvailable(index));
 
686
 
 
687
        SetDParam(0, GetEngineCategoryName(index));
 
688
        SetDParam(1, index);
 
689
        AddNewsItem(STR_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE, NS_NEW_VEHICLES, index, 0);
348
690
}
349
691
 
350
692
void EnginesMonthlyLoop()
351
693
{
352
 
        if (_cur_year < YEAR_ENGINE_AGING_STOPS) {
 
694
        if (_cur_year < _year_engine_aging_stops) {
353
695
                Engine *e;
354
696
                FOR_ALL_ENGINES(e) {
355
697
                        /* Age the vehicle */
358
700
                                CalcEngineReliability(e);
359
701
                        }
360
702
 
361
 
                        if (!(e->flags & ENGINE_AVAILABLE) && _date >= (e->intro_date + 365)) {
362
 
                                /* Introduce it to all players */
 
703
                        if (!(e->flags & ENGINE_AVAILABLE) && _date >= (e->intro_date + DAYS_IN_YEAR)) {
 
704
                                /* Introduce it to all companies */
363
705
                                NewVehicleAvailable(e);
364
 
                        } else if (!(e->flags & (ENGINE_AVAILABLE|ENGINE_EXCLUSIVE_PREVIEW)) && _date >= e->intro_date) {
365
 
                                /* Introduction date has passed.. show introducing dialog to one player. */
 
706
                        } else if (!(e->flags & (ENGINE_AVAILABLE | ENGINE_EXCLUSIVE_PREVIEW)) && _date >= e->intro_date) {
 
707
                                /* Introduction date has passed.. show introducing dialog to one companies. */
366
708
                                e->flags |= ENGINE_EXCLUSIVE_PREVIEW;
367
709
 
368
710
                                /* Do not introduce new rail wagons */
369
 
                                if (!IsWagon(e - _engines))
370
 
                                        e->preview_player_rank = 1; // Give to the player with the highest rating.
 
711
                                if (!IsWagon(e->index))
 
712
                                        e->preview_company_rank = 1; // Give to the company with the highest rating.
371
713
                        }
372
714
                }
373
715
        }
375
717
 
376
718
static bool IsUniqueEngineName(const char *name)
377
719
{
378
 
        char buf[512];
 
720
        const Engine *e;
379
721
 
380
 
        for (EngineID i = 0; i < TOTAL_NUM_ENGINES; i++) {
381
 
                SetDParam(0, i);
382
 
                GetString(buf, STR_ENGINE_NAME, lastof(buf));
383
 
                if (strcmp(buf, name) == 0) return false;
 
722
        FOR_ALL_ENGINES(e) {
 
723
                if (e->name != NULL && strcmp(e->name, name) == 0) return false;
384
724
        }
385
725
 
386
726
        return true;
392
732
 * @param p1 engine ID to rename
393
733
 * @param p2 unused
394
734
 */
395
 
CommandCost CmdRenameEngine(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
735
CommandCost CmdRenameEngine(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
396
736
{
397
 
        if (!IsEngineIndex(p1) || StrEmpty(_cmd_text)) return CMD_ERROR;
398
 
 
399
 
        if (!IsUniqueEngineName(_cmd_text)) return_cmd_error(STR_NAME_MUST_BE_UNIQUE);
 
737
        if (!IsEngineIndex(p1)) return CMD_ERROR;
 
738
 
 
739
        bool reset = StrEmpty(text);
 
740
 
 
741
        if (!reset) {
 
742
                if (strlen(text) >= MAX_LENGTH_ENGINE_NAME_BYTES) return CMD_ERROR;
 
743
                if (!IsUniqueEngineName(text)) return_cmd_error(STR_NAME_MUST_BE_UNIQUE);
 
744
        }
400
745
 
401
746
        if (flags & DC_EXEC) {
402
747
                Engine *e = GetEngine(p1);
403
748
                free(e->name);
404
 
                e->name = strdup(_cmd_text);
405
 
                _vehicle_design_names |= 3;
 
749
 
 
750
                if (reset) {
 
751
                        e->name = NULL;
 
752
                } else {
 
753
                        e->name = strdup(text);
 
754
                }
 
755
 
406
756
                MarkWholeScreenDirty();
407
757
        }
408
758
 
411
761
 
412
762
 
413
763
/** Check if an engine is buildable.
414
 
 * @param engine index of the engine to check.
415
 
 * @param type   the type the engine should be.
416
 
 * @param player index of the player.
 
764
 * @param engine  index of the engine to check.
 
765
 * @param type    the type the engine should be.
 
766
 * @param company index of the company.
417
767
 * @return True if an engine is valid, of the specified type, and buildable by
418
 
 *              the given player.
 
768
 *              the given company.
419
769
 */
420
 
bool IsEngineBuildable(EngineID engine, VehicleType type, PlayerID player)
 
770
bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company)
421
771
{
422
772
        /* check if it's an engine that is in the engine array */
423
773
        if (!IsEngineIndex(engine)) return false;
428
778
        if (e->type != type) return false;
429
779
 
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;
432
782
 
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;
437
787
        }
438
788
 
439
789
        return true;
440
790
}
441
791
 
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
 
792
/**
 
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.
445
797
 */
446
 
CargoID GetEngineCargoType(EngineID engine)
447
 
{
448
 
        assert(IsEngineIndex(engine));
449
 
 
450
 
        switch (GetEngine(engine)->type) {
451
 
                case VEH_TRAIN:
452
 
                        if (RailVehInfo(engine)->capacity == 0) return CT_INVALID;
453
 
                        return RailVehInfo(engine)->cargo_type;
454
 
 
455
 
                case VEH_ROAD:
456
 
                        if (RoadVehInfo(engine)->capacity == 0) return CT_INVALID;
457
 
                        return RoadVehInfo(engine)->cargo_type;
458
 
 
459
 
                case VEH_SHIP:
460
 
                        if (ShipVehInfo(engine)->capacity == 0) return CT_INVALID;
461
 
                        return ShipVehInfo(engine)->cargo_type;
462
 
 
463
 
                case VEH_AIRCRAFT:
464
 
                        /* all aircraft starts as passenger planes with cargo capacity */
465
 
                        return CT_PASSENGERS;
466
 
 
467
 
                default: NOT_REACHED(); return CT_INVALID;
468
 
        }
469
 
}
470
 
 
471
 
/************************************************************************
472
 
 * Engine Replacement stuff
473
 
 ************************************************************************/
474
 
 
475
 
DEFINE_OLD_POOL_GENERIC(EngineRenew, EngineRenew)
476
 
 
477
 
/**
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)
481
 
{
482
 
        EngineRenew *er = (EngineRenew *)erl;
483
 
 
484
 
        while (er) {
485
 
                if (er->from == engine && er->group_id == group) return er;
486
 
                er = er->next;
487
 
        }
488
 
        return NULL;
489
 
}
490
 
 
491
 
void RemoveAllEngineReplacement(EngineRenewList *erl)
492
 
{
493
 
        EngineRenew *er = (EngineRenew *)(*erl);
494
 
        EngineRenew *next;
495
 
 
496
 
        while (er != NULL) {
497
 
                next = er->next;
498
 
                delete er;
499
 
                er = next;
500
 
        }
501
 
        *erl = NULL; // Empty list
502
 
}
503
 
 
504
 
EngineID EngineReplacement(EngineRenewList erl, EngineID engine, GroupID group)
505
 
{
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);
510
 
        }
511
 
        return er == NULL ? INVALID_ENGINE : er->to;
512
 
}
513
 
 
514
 
CommandCost AddEngineReplacement(EngineRenewList *erl, EngineID old_engine, EngineID new_engine, GroupID group, uint32 flags)
515
 
{
516
 
        EngineRenew *er;
517
 
 
518
 
        /* Check if the old vehicle is already in the list */
519
 
        er = GetEngineReplacement(*erl, old_engine, group);
520
 
        if (er != NULL) {
521
 
                if (flags & DC_EXEC) er->to = new_engine;
522
 
                return CommandCost();
523
 
        }
524
 
 
525
 
        if (!EngineRenew::CanAllocateItem()) return CMD_ERROR;
526
 
 
527
 
        if (flags & DC_EXEC) {
528
 
                er = new EngineRenew(old_engine, new_engine);
529
 
                er->group_id = group;
530
 
 
531
 
                /* Insert before the first element */
532
 
                er->next = (EngineRenew *)(*erl);
533
 
                *erl = (EngineRenewList)er;
534
 
        }
535
 
 
536
 
        return CommandCost();
537
 
}
538
 
 
539
 
CommandCost RemoveEngineReplacement(EngineRenewList *erl, EngineID engine, GroupID group, uint32 flags)
540
 
{
541
 
        EngineRenew *er = (EngineRenew *)(*erl);
542
 
        EngineRenew *prev = NULL;
543
 
 
544
 
        while (er)
545
 
        {
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;
551
 
                                } else {
552
 
                                        /* Cut this element out */
553
 
                                        prev->next = er->next;
554
 
                                }
555
 
                                delete er;
556
 
                        }
557
 
                        return CommandCost();
558
 
                }
559
 
                prev = er;
560
 
                er = er->next;
561
 
        }
562
 
 
563
 
        return CMD_ERROR;
564
 
}
565
 
 
566
 
static const SaveLoad _engine_renew_desc[] = {
567
 
            SLE_VAR(EngineRenew, from,     SLE_UINT16),
568
 
            SLE_VAR(EngineRenew, to,       SLE_UINT16),
569
 
 
570
 
            SLE_REF(EngineRenew, next,     REF_ENGINE_RENEWS),
571
 
        SLE_CONDVAR(EngineRenew, group_id, SLE_UINT16, 60, SL_MAX_VERSION),
572
 
        SLE_END()
573
 
};
574
 
 
575
 
static void Save_ERNW()
576
 
{
577
 
        EngineRenew *er;
578
 
 
579
 
        FOR_ALL_ENGINE_RENEWS(er) {
580
 
                SlSetArrayIndex(er->index);
581
 
                SlObject(er, _engine_renew_desc);
582
 
        }
583
 
}
584
 
 
585
 
static void Load_ERNW()
586
 
{
587
 
        int index;
588
 
 
589
 
        while ((index = SlIterateArray()) != -1) {
590
 
                EngineRenew *er = new (index) EngineRenew();
591
 
                SlObject(er, _engine_renew_desc);
592
 
 
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;
598
 
                }
599
 
        }
600
 
}
601
 
 
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),
615
 
 
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),
623
 
 
624
 
        /* reserve extra space in savegame here. (currently 16 bytes) */
625
 
        SLE_CONDNULL(16, 2, SL_MAX_VERSION),
626
 
 
627
 
        SLE_END()
628
 
};
629
 
 
630
 
static void Save_ENGN()
631
 
{
632
 
        uint i;
633
 
 
634
 
        for (i = 0; i != lengthof(_engines); i++) {
635
 
                SlSetArrayIndex(i);
636
 
                SlObject(&_engines[i], _engine_desc);
637
 
        }
638
 
}
639
 
 
640
 
static void Load_ENGN()
641
 
{
642
 
        int index;
643
 
        while ((index = SlIterateArray()) != -1) {
644
 
                SlObject(GetEngine(index), _engine_desc);
645
 
        }
646
 
}
647
 
 
648
 
static void Load_ENGS()
649
 
{
650
 
        StringID names[TOTAL_NUM_ENGINES];
651
 
 
652
 
        SlArray(names, lengthof(names), SLE_STRINGID);
653
 
 
654
 
        for (EngineID engine = 0; engine < lengthof(names); engine++) {
655
 
                Engine *e = GetEngine(engine);
656
 
                e->name = CopyFromOldName(names[engine]);
657
 
        }
658
 
}
659
 
 
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},
664
 
};
665
 
 
666
 
void InitializeEngines()
667
 
{
668
 
        /* Clean the engine renew pool and create 1 block in it */
669
 
        _EngineRenew_pool.CleanPool();
670
 
        _EngineRenew_pool.AddBlockToPool();
671
 
 
672
 
        Engine *e;
673
 
        FOR_ALL_ENGINES(e) {
674
 
                free(e->name);
675
 
                e->name = NULL;
676
 
        }
 
798
bool IsEngineRefittable(EngineID engine)
 
799
{
 
800
        /* check if it's an engine that is in the engine array */
 
801
        if (!IsEngineIndex(engine)) return false;
 
802
 
 
803
        const Engine *e = GetEngine(engine);
 
804
 
 
805
        if (e->type == VEH_SHIP && !e->u.ship.refittable) return false;
 
806
 
 
807
        if (!e->CanCarryCargo()) return false;
 
808
 
 
809
        const EngineInfo *ei = &e->info;
 
810
        if (ei->refit_mask == 0) return false;
 
811
 
 
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;
 
815
 
 
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;
677
819
}