diff --git a/bin/data/openttdd.grf b/bin/data/openttdd.grf
index eaf075845d..2d4de97e3f 100644
Binary files a/bin/data/openttdd.grf and b/bin/data/openttdd.grf differ
diff --git a/bin/data/openttdw.grf b/bin/data/openttdw.grf
index c52eb3c278..c8852b4d93 100644
Binary files a/bin/data/openttdw.grf and b/bin/data/openttdw.grf differ
diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj
index 0877410820..b56616fd26 100644
--- a/projects/openttd_vs80.vcproj
+++ b/projects/openttd_vs80.vcproj
@@ -987,6 +987,10 @@
RelativePath=".\..\src\core\endian_func.hpp"
>
+
+
diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj
index 1031c2a1ee..20f9d23ccc 100644
--- a/projects/openttd_vs90.vcproj
+++ b/projects/openttd_vs90.vcproj
@@ -984,6 +984,10 @@
RelativePath=".\..\src\core\endian_func.hpp"
>
+
+
diff --git a/source.list b/source.list
index 4170e39f2c..bcf382c7b1 100644
--- a/source.list
+++ b/source.list
@@ -168,6 +168,7 @@ economy_type.h
effectvehicle_func.h
effectvehicle_base.h
core/endian_func.hpp
+engine_base.h
engine_func.h
engine_type.h
core/enum_type.hpp
diff --git a/src/ai/default/default.cpp b/src/ai/default/default.cpp
index 27a86cd65d..3a2d90c943 100644
--- a/src/ai/default/default.cpp
+++ b/src/ai/default/default.cpp
@@ -137,11 +137,11 @@ static EngineID AiChooseTrainToBuild(RailType railtype, Money money, byte flag,
{
EngineID best_veh_index = INVALID_ENGINE;
byte best_veh_score = 0;
- EngineID i;
+ const Engine *e;
- FOR_ALL_ENGINEIDS_OF_TYPE(i, VEH_TRAIN) {
- const RailVehicleInfo *rvi = RailVehInfo(i);
- const Engine* e = GetEngine(i);
+ FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) {
+ EngineID i = e->index;
+ const RailVehicleInfo *rvi = &e->u.rail;
if (!IsCompatibleRail(rvi->railtype, railtype) ||
rvi->railveh_type == RAILVEH_WAGON ||
@@ -168,11 +168,11 @@ static EngineID AiChooseRoadVehToBuild(CargoID cargo, Money money, TileIndex til
{
EngineID best_veh_index = INVALID_ENGINE;
int32 best_veh_rating = 0;
- EngineID i;
+ const Engine *e;
- FOR_ALL_ENGINEIDS_OF_TYPE(i, VEH_ROAD) {
- const RoadVehicleInfo *rvi = RoadVehInfo(i);
- const Engine* e = GetEngine(i);
+ FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) {
+ EngineID i = e->index;
+ const RoadVehicleInfo *rvi = &e->u.road;
if (!HasBit(e->player_avail, _current_player) || e->reliability < 0x8A3D) {
continue;
@@ -209,16 +209,17 @@ static EngineID AiChooseAircraftToBuild(Money money, byte forbidden)
{
EngineID best_veh_index = INVALID_ENGINE;
Money best_veh_cost = 0;
- EngineID i;
+ const Engine *e;
- FOR_ALL_ENGINEIDS_OF_TYPE(i, VEH_AIRCRAFT) {
- const Engine* e = GetEngine(i);
+ FOR_ALL_ENGINES_OF_TYPE(e, VEH_AIRCRAFT) {
+ EngineID i = e->index;
+ const AircraftVehicleInfo *avi = &e->u.air;
if (!HasBit(e->player_avail, _current_player) || e->reliability < 0x8A3D) {
continue;
}
- if ((AircraftVehInfo(i)->subtype & forbidden) != 0) continue;
+ if ((avi->subtype & forbidden) != 0) continue;
CommandCost ret = DoCommand(0, i, 0, DC_QUERY_COST, CMD_BUILD_AIRCRAFT);
if (CmdSucceeded(ret) && ret.GetCost() <= money && ret.GetCost() >= best_veh_cost) {
@@ -2445,14 +2446,14 @@ static StationID AiGetStationIdByDef(TileIndex tile, int id)
static EngineID AiFindBestWagon(CargoID cargo, RailType railtype)
{
EngineID best_veh_index = INVALID_ENGINE;
- EngineID i;
uint16 best_capacity = 0;
uint16 best_speed = 0;
uint speed;
+ const Engine *e;
- FOR_ALL_ENGINEIDS_OF_TYPE(i, VEH_TRAIN) {
- const RailVehicleInfo *rvi = RailVehInfo(i);
- const Engine* e = GetEngine(i);
+ FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) {
+ EngineID i = e->index;
+ const RailVehicleInfo *rvi = &e->u.rail;
if (!IsCompatibleRail(rvi->railtype, railtype) ||
rvi->railveh_type != RAILVEH_WAGON ||
diff --git a/src/ai/trolly/build.cpp b/src/ai/trolly/build.cpp
index b46984d0a7..eb71540929 100644
--- a/src/ai/trolly/build.cpp
+++ b/src/ai/trolly/build.cpp
@@ -7,6 +7,7 @@
#include "../../command_func.h"
#include "trolly.h"
#include "../../engine_func.h"
+#include "../../engine_base.h"
#include "../../variables.h"
#include "../../bridge.h"
#include "../../vehicle_func.h"
@@ -235,12 +236,12 @@ EngineID AiNew_PickVehicle(Player *p)
} else {
EngineID best_veh_index = INVALID_ENGINE;
int32 best_veh_rating = 0;
- EngineID i;
+ const Engine *e;
/* Loop through all road vehicles */
- FOR_ALL_ENGINEIDS_OF_TYPE(i, VEH_ROAD) {
- const RoadVehicleInfo *rvi = RoadVehInfo(i);
- const Engine* e = GetEngine(i);
+ FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) {
+ EngineID i = e->index;
+ const RoadVehicleInfo *rvi = &e->u.road;
/* Skip vehicles which can't take our cargo type */
if (rvi->cargo_type != _players_ainew[p->index].cargo && !CanRefitTo(i, _players_ainew[p->index].cargo)) continue;
diff --git a/src/ai/trolly/trolly.cpp b/src/ai/trolly/trolly.cpp
index 49133386df..2a369cd03c 100644
--- a/src/ai/trolly/trolly.cpp
+++ b/src/ai/trolly/trolly.cpp
@@ -29,6 +29,7 @@
#include "../../industry.h"
#include "../../station_base.h"
#include "../../engine_func.h"
+#include "../../engine_base.h"
#include "../../gui.h"
#include "../../depot_base.h"
#include "../../vehicle_base.h"
diff --git a/src/aircraft.h b/src/aircraft.h
index bfb8c3b93e..cef1debd1e 100644
--- a/src/aircraft.h
+++ b/src/aircraft.h
@@ -9,6 +9,7 @@
#include "station_base.h"
#include "vehicle_base.h"
#include "engine_func.h"
+#include "engine_base.h"
/** An aircraft can be one ot those types */
enum AircraftSubType {
diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp
index c0795b6fbe..197bb24b09 100644
--- a/src/aircraft_cmd.cpp
+++ b/src/aircraft_cmd.cpp
@@ -168,7 +168,7 @@ SpriteID Aircraft::GetImage(Direction direction) const
SpriteID sprite = GetCustomVehicleSprite(this, direction);
if (sprite != 0) return sprite;
- spritenum = _orig_aircraft_vehicle_info[this->engine_type - AIRCRAFT_ENGINES_INDEX].image_index;
+ spritenum = GetEngine(this->engine_type)->image_index;
}
return direction + _aircraft_sprite[spritenum];
@@ -196,7 +196,7 @@ static SpriteID GetAircraftIcon(EngineID engine)
SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W);
if (sprite != 0) return sprite;
- spritenum = _orig_aircraft_vehicle_info[engine - AIRCRAFT_ENGINES_INDEX].image_index;
+ spritenum = GetEngine(engine)->image_index;
}
return 6 + _aircraft_sprite[spritenum];
diff --git a/src/articulated_vehicles.cpp b/src/articulated_vehicles.cpp
index ef63e71b54..d6e1a97d28 100644
--- a/src/articulated_vehicles.cpp
+++ b/src/articulated_vehicles.cpp
@@ -11,6 +11,19 @@
#include "newgrf_engine.h"
#include "vehicle_func.h"
+static EngineID GetNewEngineID(const GRFFile *file, VehicleType type, uint16 internal_id)
+{
+ const Engine *e = NULL;
+ FOR_ALL_ENGINES(e) {
+ if (e->grffile != file) continue;
+ if (e->type != type) continue;
+ if (e->internal_id != internal_id) continue;
+
+ return e->index;
+ }
+
+ return INVALID_ENGINE;
+}
uint CountArticulatedParts(EngineID engine_type, bool purchase_window)
{
@@ -54,7 +67,7 @@ uint16 *GetCapacityOfArticulatedParts(EngineID engine, VehicleType type)
uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, engine, NULL);
if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) break;
- EngineID artic_engine = GetFirstEngineOfType(type) + GB(callback, 0, 7);
+ EngineID artic_engine = GetNewEngineID(GetEngineGRF(engine), type, GB(callback, 0, 7));
if (type == VEH_TRAIN) {
const RailVehicleInfo *rvi = RailVehInfo(artic_engine);
@@ -88,7 +101,7 @@ void AddArticulatedParts(Vehicle **vl, VehicleType type)
Vehicle *previous = u;
u = u->Next();
- EngineID engine_type = GetFirstEngineOfType(type) + GB(callback, 0, 7);
+ EngineID engine_type = GetNewEngineID(GetEngineGRF(v->engine_type), type, GB(callback, 0, 7));
bool flip_image = HasBit(callback, 7);
/* get common values from first engine */
diff --git a/src/autoreplace_gui.cpp b/src/autoreplace_gui.cpp
index 7dc37ab3b6..a980d59c0c 100644
--- a/src/autoreplace_gui.cpp
+++ b/src/autoreplace_gui.cpp
@@ -20,6 +20,7 @@
#include "player_func.h"
#include "widgets/dropdown_func.h"
#include "engine_func.h"
+#include "engine_base.h"
#include "table/sprites.h"
#include "table/strings.h"
@@ -198,8 +199,9 @@ static void GenerateReplaceVehList(Window *w, bool draw_left)
EngineList *list = &WP(w, replaceveh_d).list[i];
EngList_RemoveAll(list);
- EngineID eid;
- FOR_ALL_ENGINEIDS_OF_TYPE(eid, type) {
+ const Engine *e;
+ FOR_ALL_ENGINES_OF_TYPE(e, type) {
+ EngineID eid = e->index;
if (type == VEH_TRAIN && !GenerateReplaceRailList(eid, draw_left, WP(w, replaceveh_d).wagon_btnstate)) continue; // special rules for trains
if (draw_left) {
@@ -214,7 +216,7 @@ static void GenerateReplaceVehList(Window *w, bool draw_left)
if (!EnginesGotCargoInCommon(eid, WP(w, replaceveh_d).sel_engine[0])) continue; // the engines needs to be able to carry the same cargo
/* Road vehicles can't be replaced by trams and vice-versa */
- if (type == VEH_ROAD && HasBit(EngInfo(WP(w, replaceveh_d).sel_engine[0])->misc_flags, EF_ROAD_TRAM) != HasBit(EngInfo(eid)->misc_flags, EF_ROAD_TRAM)) continue;
+ if (type == VEH_ROAD && HasBit(EngInfo(WP(w, replaceveh_d).sel_engine[0])->misc_flags, EF_ROAD_TRAM) != HasBit(e->info.misc_flags, EF_ROAD_TRAM)) continue;
if (eid == WP(w, replaceveh_d).sel_engine[0]) continue; // we can't replace an engine into itself (that would be autorenew)
}
diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp
index 5174a949e1..3170377236 100644
--- a/src/build_vehicle_gui.cpp
+++ b/src/build_vehicle_gui.cpp
@@ -800,9 +800,10 @@ static void GenerateBuildTrainList(Window *w)
* Also check to see if the previously selected engine is still available,
* and if not, reset selection to INVALID_ENGINE. This could be the case
* when engines become obsolete and are removed */
- EngineID eid;
- FOR_ALL_ENGINEIDS_OF_TYPE(eid, VEH_TRAIN) {
- const RailVehicleInfo *rvi = RailVehInfo(eid);
+ const Engine *e;
+ FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) {
+ EngineID eid = e->index;
+ const RailVehicleInfo *rvi = &e->u.rail;
if (bv->filter.railtype != RAILTYPE_END && !HasPowerOnRail(rvi->railtype, bv->filter.railtype)) continue;
if (!IsEngineBuildable(eid, VEH_TRAIN, _local_player)) continue;
@@ -839,8 +840,9 @@ static void GenerateBuildRoadVehList(Window *w)
EngList_RemoveAll(&bv->eng_list);
- EngineID eid;
- FOR_ALL_ENGINEIDS_OF_TYPE(eid, VEH_ROAD) {
+ const Engine *e;
+ FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) {
+ EngineID eid = e->index;
if (!IsEngineBuildable(eid, VEH_ROAD, _local_player)) continue;
if (!HasBit(bv->filter.roadtypes, HasBit(EngInfo(eid)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD)) continue;
EngList_Add(&bv->eng_list, eid);
@@ -858,8 +860,9 @@ static void GenerateBuildShipList(Window *w)
EngList_RemoveAll(&bv->eng_list);
- EngineID eid;
- FOR_ALL_ENGINEIDS_OF_TYPE(eid, VEH_SHIP) {
+ const Engine *e;
+ FOR_ALL_ENGINES_OF_TYPE(e, VEH_SHIP) {
+ EngineID eid = e->index;
if (!IsEngineBuildable(eid, VEH_SHIP, _local_player)) continue;
EngList_Add(&bv->eng_list, eid);
@@ -880,8 +883,9 @@ static void GenerateBuildAircraftList(Window *w)
* Also check to see if the previously selected plane is still available,
* and if not, reset selection to INVALID_ENGINE. This could be the case
* when planes become obsolete and are removed */
- EngineID eid;
- FOR_ALL_ENGINEIDS_OF_TYPE(eid, VEH_AIRCRAFT) {
+ const Engine *e;
+ FOR_ALL_ENGINES_OF_TYPE(e, VEH_AIRCRAFT) {
+ EngineID eid = e->index;
if (!IsEngineBuildable(eid, VEH_AIRCRAFT, _local_player)) continue;
/* First VEH_END window_numbers are fake to allow a window open for all different types at once */
if (w->window_number > VEH_END && !CanAircraftUseStation(eid, w->window_number)) continue;
diff --git a/src/depot_gui.cpp b/src/depot_gui.cpp
index e88fb6de8c..7a859b1bc3 100644
--- a/src/depot_gui.cpp
+++ b/src/depot_gui.cpp
@@ -656,8 +656,9 @@ static void ResizeDefaultWindowSize(VehicleType type)
uint max_width = 0;
uint max_height = 0;
- EngineID eid;
- FOR_ALL_ENGINEIDS_OF_TYPE(eid, type) {
+ const Engine *e;
+ FOR_ALL_ENGINES_OF_TYPE(e, type) {
+ EngineID eid = e->index;
uint x, y;
switch (type) {
diff --git a/src/elrail.cpp b/src/elrail.cpp
index c999c4375c..6e776ea0ac 100644
--- a/src/elrail.cpp
+++ b/src/elrail.cpp
@@ -66,6 +66,7 @@
#include "player_base.h"
#include "tunnelbridge.h"
#include "engine_func.h"
+#include "engine_base.h"
#include "table/sprites.h"
#include "table/elrail_data.h"
@@ -480,9 +481,9 @@ int32 SettingsDisableElrail(int32 p1)
const RailType new_railtype = disable ? RAILTYPE_RAIL : RAILTYPE_ELECTRIC;
/* walk through all train engines */
- EngineID eid;
- FOR_ALL_ENGINEIDS_OF_TYPE(eid, VEH_TRAIN) {
- RailVehicleInfo *rv_info = &_rail_vehicle_info[eid];
+ Engine *e;
+ FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) {
+ RailVehicleInfo *rv_info = &e->u.rail;
/* if it is an electric rail engine and its railtype is the wrong one */
if (rv_info->engclass == 2 && rv_info->railtype == old_railtype) {
/* change it to the proper one */
diff --git a/src/engine.cpp b/src/engine.cpp
index 3bc0657c29..c721e31a1d 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -14,6 +14,7 @@
#include "train.h"
#include "aircraft.h"
#include "newgrf_cargo.h"
+#include "newgrf_engine.h"
#include "group.h"
#include "strings_func.h"
#include "gfx_func.h"
@@ -25,45 +26,105 @@
#include "string_func.h"
#include "settings_type.h"
#include "oldpool_func.h"
+#include "core/alloc_func.hpp"
+#include "map"
#include "table/strings.h"
#include "table/engines.h"
-Engine _engines[TOTAL_NUM_ENGINES];
-EngineInfo _engine_info[TOTAL_NUM_ENGINES];
-RailVehicleInfo _rail_vehicle_info[NUM_TRAIN_ENGINES];
-ShipVehicleInfo _ship_vehicle_info[NUM_SHIP_ENGINES];
-AircraftVehicleInfo _aircraft_vehicle_info[NUM_AIRCRAFT_ENGINES];
-RoadVehicleInfo _road_vehicle_info[NUM_ROAD_ENGINES];
+DEFINE_OLD_POOL_GENERIC(Engine, Engine)
enum {
YEAR_ENGINE_AGING_STOPS = 2050,
};
-void SetupEngines()
+/** Number of engines of each vehicle type in original engine data */
+const uint8 _engine_counts[4] = {
+ lengthof(_orig_rail_vehicle_info),
+ lengthof(_orig_road_vehicle_info),
+ lengthof(_orig_ship_vehicle_info),
+ lengthof(_orig_aircraft_vehicle_info),
+};
+
+/** Offset of the first engine of each vehicle type in original engine data */
+const uint8 _engine_offsets[4] = {
+ 0,
+ lengthof(_orig_rail_vehicle_info),
+ lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info),
+ lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info) + lengthof(_orig_ship_vehicle_info),
+};
+
+Engine::Engine() :
+ name(NULL),
+ overrides_count(0),
+ overrides(NULL)
+{
+}
+
+Engine::Engine(VehicleType type, EngineID base)
{
- /* Copy original static engine data */
- memcpy(&_engine_info, &_orig_engine_info, sizeof(_orig_engine_info));
- memcpy(&_rail_vehicle_info, &_orig_rail_vehicle_info, sizeof(_orig_rail_vehicle_info));
- memcpy(&_ship_vehicle_info, &_orig_ship_vehicle_info, sizeof(_orig_ship_vehicle_info));
- memcpy(&_aircraft_vehicle_info, &_orig_aircraft_vehicle_info, sizeof(_orig_aircraft_vehicle_info));
- memcpy(&_road_vehicle_info, &_orig_road_vehicle_info, sizeof(_orig_road_vehicle_info));
-
- /* Add type to engines */
- Engine* e = _engines;
- do e->type = VEH_TRAIN; while (++e < &_engines[ROAD_ENGINES_INDEX]);
- do e->type = VEH_ROAD; while (++e < &_engines[SHIP_ENGINES_INDEX]);
- do e->type = VEH_SHIP; while (++e < &_engines[AIRCRAFT_ENGINES_INDEX]);
- do e->type = VEH_AIRCRAFT; while (++e < &_engines[TOTAL_NUM_ENGINES]);
-
- /* Set up default engine names */
- for (EngineID engine = 0; engine < TOTAL_NUM_ENGINES; engine++) {
- EngineInfo *ei = &_engine_info[engine];
- ei->string_id = STR_8000_KIRBY_PAUL_TANK_STEAM + engine;
+ this->type = type;
+ this->internal_id = base;
+ this->list_position = base;
+
+ /* Check if this base engine is within the original engine data range */
+ if (base >= _engine_counts[type]) {
+ /* Mark engine as valid anyway */
+ this->info.climates = 0x80;
+ return;
+ }
+
+ /* Copy the original engine info for this slot */
+ this->info = _orig_engine_info[_engine_offsets[type] + base];
+
+ /* Copy the original engine data for this slot */
+ switch (type) {
+ default: NOT_REACHED();
+
+ case VEH_TRAIN:
+ this->u.rail = _orig_rail_vehicle_info[base];
+ this->image_index = this->u.rail.image_index;
+ this->info.string_id = STR_8000_KIRBY_PAUL_TANK_STEAM + base;
+ break;
+
+ case VEH_ROAD:
+ this->u.road = _orig_road_vehicle_info[base];
+ this->image_index = this->u.road.image_index;
+ this->info.string_id = STR_8074_MPS_REGAL_BUS + base;
+ break;
+
+ case VEH_SHIP:
+ this->u.ship = _orig_ship_vehicle_info[base];
+ this->image_index = this->u.ship.image_index;
+ this->info.string_id = STR_80CC_MPS_OIL_TANKER + base;
+ break;
+
+ case VEH_AIRCRAFT:
+ this->u.air = _orig_aircraft_vehicle_info[base];
+ this->image_index = this->u.air.image_index;
+ this->info.string_id = STR_80D7_SAMPSON_U52 + base;
+ break;
}
}
+Engine::~Engine()
+{
+ UnloadWagonOverrides(this);
+ free(this->name);
+}
+
+void SetupEngines()
+{
+ _Engine_pool.CleanPool();
+ _Engine_pool.AddBlockToPool();
+
+ for (uint i = 0; i < lengthof(_orig_rail_vehicle_info); i++) new Engine(VEH_TRAIN, i);
+ for (uint i = 0; i < lengthof(_orig_road_vehicle_info); i++) new Engine(VEH_ROAD, i);
+ for (uint i = 0; i < lengthof(_orig_ship_vehicle_info); i++) new Engine(VEH_SHIP, i);
+ for (uint i = 0; i < lengthof(_orig_aircraft_vehicle_info); i++) new Engine(VEH_AIRCRAFT, i);
+}
+
void ShowEnginePreviewWindow(EngineID engine);
@@ -90,7 +151,7 @@ static void CalcEngineReliability(Engine *e)
/* Check for early retirement */
if (e->player_avail != 0 && !_patches.never_expire_vehicles) {
- int retire_early = EngInfo(e - _engines)->retire_early;
+ int retire_early = e->info.retire_early;
uint retire_early_max_age = max(0, e->duration_phase_1 + e->duration_phase_2 - retire_early * 12);
if (retire_early != 0 && age >= retire_early_max_age) {
/* Early retirement is enabled and we're past the date... */
@@ -124,11 +185,11 @@ static void CalcEngineReliability(Engine *e)
void StartupEngines()
{
Engine *e;
- const EngineInfo *ei;
/* Aging of vehicles stops, so account for that when starting late */
const Date aging_date = min(_date, ConvertYMDToDate(YEAR_ENGINE_AGING_STOPS, 0, 1));
- for (e = _engines, ei = _engine_info; e != endof(_engines); e++, ei++) {
+ FOR_ALL_ENGINES(e) {
+ const EngineInfo *ei = &e->info;
uint32 r;
e->age = 0;
@@ -224,13 +285,11 @@ static PlayerID GetBestPlayer(uint8 pp)
void EnginesDailyLoop()
{
- EngineID i;
-
if (_cur_year >= YEAR_ENGINE_AGING_STOPS) return;
- for (i = 0; i != lengthof(_engines); i++) {
- Engine *e = &_engines[i];
-
+ Engine *e;
+ FOR_ALL_ENGINES(e) {
+ EngineID i = e->index;
if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) {
if (e->flags & ENGINE_OFFER_WINDOW_OPEN) {
if (e->preview_player_rank != 0xFF && !--e->preview_wait) {
@@ -282,14 +341,15 @@ CommandCost CmdWantEnginePreview(TileIndex tile, uint32 flags, uint32 p1, uint32
/* Determine if an engine type is a wagon (and not a loco) */
static bool IsWagon(EngineID index)
{
- return index < NUM_TRAIN_ENGINES && RailVehInfo(index)->railveh_type == RAILVEH_WAGON;
+ const Engine *e = GetEngine(index);
+ return e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON;
}
static void NewVehicleAvailable(Engine *e)
{
Vehicle *v;
Player *p;
- EngineID index = e - _engines;
+ EngineID index = e->index;
/* In case the player didn't build the vehicle during the intro period,
* prevent that player from getting future intro periods for a while. */
@@ -326,7 +386,7 @@ static void NewVehicleAvailable(Engine *e)
if (e->type == VEH_TRAIN) {
/* maybe make another rail type available */
- RailType railtype = RailVehInfo(index)->railtype;
+ RailType railtype = e->u.rail.railtype;
assert(railtype < RAILTYPE_END);
FOR_ALL_PLAYERS(p) {
if (p->is_active) SetBit(p->avail_railtypes, railtype);
@@ -334,7 +394,7 @@ static void NewVehicleAvailable(Engine *e)
} else if (e->type == VEH_ROAD) {
/* maybe make another road type available */
FOR_ALL_PLAYERS(p) {
- if (p->is_active) SetBit(p->avail_roadtypes, HasBit(EngInfo(index)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD);
+ if (p->is_active) SetBit(p->avail_roadtypes, HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD);
}
}
AddNewsItem(index, NM_CALLBACK, NF_NONE, NT_NEW_VEHICLES, DNC_VEHICLEAVAIL, 0, 0);
@@ -359,7 +419,7 @@ void EnginesMonthlyLoop()
e->flags |= ENGINE_EXCLUSIVE_PREVIEW;
/* Do not introduce new rail wagons */
- if (!IsWagon(e - _engines))
+ if (!IsWagon(e->index))
e->preview_player_rank = 1; // Give to the player with the highest rating.
}
}
@@ -370,8 +430,9 @@ static bool IsUniqueEngineName(const char *name)
{
char buf[512];
- for (EngineID i = 0; i < TOTAL_NUM_ENGINES; i++) {
- SetDParam(0, i);
+ const Engine *e;
+ FOR_ALL_ENGINES(e) {
+ SetDParam(0, e->index);
GetString(buf, STR_ENGINE_NAME, lastof(buf));
if (strcmp(buf, name) == 0) return false;
}
@@ -620,32 +681,77 @@ static const SaveLoad _engine_desc[] = {
SLE_END()
};
-static void Save_ENGN()
+static std::map _temp_engine;
+
+Engine *GetTempDataEngine(EngineID index)
{
- uint i;
+ return &_temp_engine[index];
+}
- for (i = 0; i != lengthof(_engines); i++) {
- SlSetArrayIndex(i);
- SlObject(&_engines[i], _engine_desc);
+static void Save_ENGN()
+{
+ Engine *e;
+ FOR_ALL_ENGINES(e) {
+ SlSetArrayIndex(e->index);
+ SlObject(e, _engine_desc);
}
}
static void Load_ENGN()
{
+ /* As engine data is loaded before engines are initialized we need to load
+ * this information into a temporary array. This is then copied into the
+ * engine pool after processing NewGRFs by CopyTempEngineData(). */
int index;
while ((index = SlIterateArray()) != -1) {
- SlObject(GetEngine(index), _engine_desc);
+ Engine *e = GetTempDataEngine(index);
+ SlObject(e, _engine_desc);
}
}
+/**
+ * Copy data from temporary engine array into the real engine pool.
+ */
+void CopyTempEngineData()
+{
+ Engine *e;
+ FOR_ALL_ENGINES(e) {
+ if (e->index >= _temp_engine.size()) break;
+
+ const Engine *se = GetTempDataEngine(e->index);
+ e->intro_date = se->intro_date;
+ e->age = se->age;
+ e->reliability = se->reliability;
+ e->reliability_spd_dec = se->reliability_spd_dec;
+ e->reliability_start = se->reliability_start;
+ e->reliability_max = se->reliability_max;
+ e->reliability_final = se->reliability_final;
+ e->duration_phase_1 = se->duration_phase_1;
+ e->duration_phase_2 = se->duration_phase_2;
+ e->duration_phase_3 = se->duration_phase_3;
+ e->lifelength = se->lifelength;
+ e->flags = se->flags;
+ e->preview_player_rank = se->preview_player_rank;
+ e->preview_wait = se->preview_wait;
+ e->player_avail = se->player_avail;
+ if (se->name != NULL) e->name = strdup(se->name);
+ }
+
+ /* Get rid of temporary data */
+ _temp_engine.clear();
+}
+
static void Load_ENGS()
{
- StringID names[TOTAL_NUM_ENGINES];
+ /* Load old separate String ID list into a temporary array. This
+ * was always 256 entries. */
+ StringID names[256];
SlArray(names, lengthof(names), SLE_STRINGID);
+ /* Copy each string into the temporary engine array. */
for (EngineID engine = 0; engine < lengthof(names); engine++) {
- Engine *e = GetEngine(engine);
+ Engine *e = GetTempDataEngine(engine);
e->name = CopyFromOldName(names[engine]);
}
}
@@ -661,10 +767,4 @@ void InitializeEngines()
/* Clean the engine renew pool and create 1 block in it */
_EngineRenew_pool.CleanPool();
_EngineRenew_pool.AddBlockToPool();
-
- Engine *e;
- FOR_ALL_ENGINES(e) {
- free(e->name);
- e->name = NULL;
- }
}
diff --git a/src/engine_base.h b/src/engine_base.h
new file mode 100644
index 0000000000..cff59fcb20
--- /dev/null
+++ b/src/engine_base.h
@@ -0,0 +1,88 @@
+/* $Id$ */
+
+/** @file engine_base.h Base class for engines. */
+
+#ifndef ENGINE_BASE_H
+#define ENGINE_BASE_H
+
+#include "engine_type.h"
+#include "oldpool.h"
+
+DECLARE_OLD_POOL(Engine, Engine, 6, 10000)
+
+struct Engine : PoolItem {
+ char *name; ///< Custom name of engine
+ Date intro_date;
+ Date age;
+ uint16 reliability;
+ uint16 reliability_spd_dec;
+ uint16 reliability_start, reliability_max, reliability_final;
+ uint16 duration_phase_1, duration_phase_2, duration_phase_3;
+ byte lifelength;
+ byte flags;
+ uint8 preview_player_rank;
+ byte preview_wait;
+ byte player_avail;
+ uint8 image_index; ///< Original vehicle image index
+ VehicleType type; ///< type, ie VEH_ROAD, VEH_TRAIN, etc.
+
+ EngineInfo info;
+
+ union {
+ RailVehicleInfo rail;
+ RoadVehicleInfo road;
+ ShipVehicleInfo ship;
+ AircraftVehicleInfo air;
+ } u;
+
+ /* NewGRF related data */
+ const struct GRFFile *grffile;
+ const struct SpriteGroup *group[NUM_CARGO + 2];
+ uint16 internal_id; ///< ID within the GRF file
+ uint16 overrides_count;
+ struct WagonOverride *overrides;
+ uint16 list_position;
+
+ Engine();
+ Engine(VehicleType type, EngineID base);
+ ~Engine();
+
+ inline bool IsValid() const { return this->info.climates != 0; }
+};
+
+static inline bool IsEngineIndex(uint index)
+{
+ return index < GetEnginePoolSize();
+}
+
+#define FOR_ALL_ENGINES_FROM(e, start) for (e = GetEngine(start); e != NULL; e = (e->index + 1U < GetEnginePoolSize()) ? GetEngine(e->index + 1U) : NULL) if (e->IsValid())
+#define FOR_ALL_ENGINES(e) FOR_ALL_ENGINES_FROM(e, 0)
+
+#define FOR_ALL_ENGINES_OF_TYPE(e, engine_type) FOR_ALL_ENGINES(e) if (e->type == engine_type)
+
+static inline const EngineInfo *EngInfo(EngineID e)
+{
+ return &GetEngine(e)->info;
+}
+
+static inline const RailVehicleInfo *RailVehInfo(EngineID e)
+{
+ return &GetEngine(e)->u.rail;
+}
+
+static inline const RoadVehicleInfo *RoadVehInfo(EngineID e)
+{
+ return &GetEngine(e)->u.road;
+}
+
+static inline const ShipVehicleInfo *ShipVehInfo(EngineID e)
+{
+ return &GetEngine(e)->u.ship;
+}
+
+static inline const AircraftVehicleInfo *AircraftVehInfo(EngineID e)
+{
+ return &GetEngine(e)->u.air;
+}
+
+#endif /* ENGINE_TYPE_H */
diff --git a/src/engine_func.h b/src/engine_func.h
index 387cf55523..a5cc164539 100644
--- a/src/engine_func.h
+++ b/src/engine_func.h
@@ -10,6 +10,12 @@
void SetupEngines();
void StartupEngines();
+Engine *GetTempDataEngine(EngineID index);
+void CopyTempEngineData();
+
+/* Original engine data counts and offsets */
+extern const uint8 _engine_counts[4];
+extern const uint8 _engine_offsets[4];
void DrawTrainEngine(int x, int y, EngineID engine, SpriteID pal);
void DrawRoadVehEngine(int x, int y, EngineID engine, SpriteID pal);
@@ -22,83 +28,6 @@ void DeleteCustomEngineNames();
bool IsEngineBuildable(EngineID engine, VehicleType type, PlayerID player);
CargoID GetEngineCargoType(EngineID engine);
-static inline EngineID GetFirstEngineOfType(VehicleType type)
-{
- const EngineID start[] = {0, ROAD_ENGINES_INDEX, SHIP_ENGINES_INDEX, AIRCRAFT_ENGINES_INDEX};
-
- return start[type];
-}
-
-static inline EngineID GetLastEngineOfType(VehicleType type)
-{
- const EngineID end[] = {
- NUM_TRAIN_ENGINES,
- ROAD_ENGINES_INDEX + NUM_ROAD_ENGINES,
- SHIP_ENGINES_INDEX + NUM_SHIP_ENGINES,
- AIRCRAFT_ENGINES_INDEX + NUM_AIRCRAFT_ENGINES};
-
- return end[type];
-}
-
-extern Engine _engines[TOTAL_NUM_ENGINES];
-#define FOR_ALL_ENGINES(e) for (e = _engines; e != endof(_engines); e++)
-#define FOR_ALL_ENGINEIDS_OF_TYPE(e, type) for (e = GetFirstEngineOfType(type); e != GetLastEngineOfType(type); e++)
-
-
-static inline Engine* GetEngine(EngineID i)
-{
- assert(i < lengthof(_engines));
- return &_engines[i];
-}
-
-static inline bool IsEngineIndex(uint index)
-{
- return index < TOTAL_NUM_ENGINES;
-}
-
-/* Access Vehicle Data */
-extern const EngineInfo _orig_engine_info[TOTAL_NUM_ENGINES];
-extern const RailVehicleInfo _orig_rail_vehicle_info[NUM_TRAIN_ENGINES];
-extern const ShipVehicleInfo _orig_ship_vehicle_info[NUM_SHIP_ENGINES];
-extern const AircraftVehicleInfo _orig_aircraft_vehicle_info[NUM_AIRCRAFT_ENGINES];
-extern const RoadVehicleInfo _orig_road_vehicle_info[NUM_ROAD_ENGINES];
-
-extern EngineInfo _engine_info[TOTAL_NUM_ENGINES];
-extern RailVehicleInfo _rail_vehicle_info[NUM_TRAIN_ENGINES];
-extern ShipVehicleInfo _ship_vehicle_info[NUM_SHIP_ENGINES];
-extern AircraftVehicleInfo _aircraft_vehicle_info[NUM_AIRCRAFT_ENGINES];
-extern RoadVehicleInfo _road_vehicle_info[NUM_ROAD_ENGINES];
-
-static inline const EngineInfo *EngInfo(EngineID e)
-{
- assert(e < lengthof(_engine_info));
- return &_engine_info[e];
-}
-
-static inline const RailVehicleInfo* RailVehInfo(EngineID e)
-{
- assert(e < lengthof(_rail_vehicle_info));
- return &_rail_vehicle_info[e];
-}
-
-static inline const ShipVehicleInfo* ShipVehInfo(EngineID e)
-{
- assert(e >= SHIP_ENGINES_INDEX && e < SHIP_ENGINES_INDEX + lengthof(_ship_vehicle_info));
- return &_ship_vehicle_info[e - SHIP_ENGINES_INDEX];
-}
-
-static inline const AircraftVehicleInfo* AircraftVehInfo(EngineID e)
-{
- assert(e >= AIRCRAFT_ENGINES_INDEX && e < AIRCRAFT_ENGINES_INDEX + lengthof(_aircraft_vehicle_info));
- return &_aircraft_vehicle_info[e - AIRCRAFT_ENGINES_INDEX];
-}
-
-static inline const RoadVehicleInfo* RoadVehInfo(EngineID e)
-{
- assert(e >= ROAD_ENGINES_INDEX && e < ROAD_ENGINES_INDEX + lengthof(_road_vehicle_info));
- return &_road_vehicle_info[e - ROAD_ENGINES_INDEX];
-}
-
/* Engine list manipulators - current implementation is only C wrapper of CBlobT class (helpers.cpp) */
void EngList_Create(EngineList *el); ///< Creates engine list
void EngList_Destroy(EngineList *el); ///< Deallocate and destroy engine list
diff --git a/src/engine_gui.cpp b/src/engine_gui.cpp
index cf0b83f7f1..9e1d3c80a9 100644
--- a/src/engine_gui.cpp
+++ b/src/engine_gui.cpp
@@ -8,6 +8,7 @@
#include "window_gui.h"
#include "gfx_func.h"
#include "engine_func.h"
+#include "engine_base.h"
#include "command_func.h"
#include "economy_func.h"
#include "news_func.h"
diff --git a/src/engine_type.h b/src/engine_type.h
index 6079cdc6af..03bee6fe4f 100644
--- a/src/engine_type.h
+++ b/src/engine_type.h
@@ -18,6 +18,8 @@ typedef uint16 EngineID;
typedef uint16 EngineRenewID;
typedef EngineID *EngineList; ///< engine list type placeholder acceptable for C code (see helpers.cpp)
+struct Engine;
+
enum RailVehicleTypes {
RAILVEH_SINGLEHEAD, ///< indicates a "standalone" locomotive
RAILVEH_MULTIHEAD, ///< indicates a combination of two locomotives
@@ -119,22 +121,6 @@ struct EngineInfo {
StringID string_id; ///< Default name of engine
};
-struct Engine {
- char *name; ///< Custom name of engine
- Date intro_date;
- Date age;
- uint16 reliability;
- uint16 reliability_spd_dec;
- uint16 reliability_start, reliability_max, reliability_final;
- uint16 duration_phase_1, duration_phase_2, duration_phase_3;
- byte lifelength;
- byte flags;
- uint8 preview_player_rank;
- byte preview_wait;
- byte player_avail;
- VehicleType type; ///< type, ie VEH_ROAD, VEH_TRAIN, etc.
-};
-
/**
* EngineInfo.misc_flags is a bitmask, with the following values
*/
@@ -160,18 +146,4 @@ enum {
static const EngineID INVALID_ENGINE = 0xFFFF;
-enum {
- NUM_NORMAL_RAIL_ENGINES = 54,
- NUM_MONORAIL_ENGINES = 30,
- NUM_MAGLEV_ENGINES = 32,
- NUM_TRAIN_ENGINES = NUM_NORMAL_RAIL_ENGINES + NUM_MONORAIL_ENGINES + NUM_MAGLEV_ENGINES,
- NUM_ROAD_ENGINES = 88,
- NUM_SHIP_ENGINES = 11,
- NUM_AIRCRAFT_ENGINES = 41,
- TOTAL_NUM_ENGINES = NUM_TRAIN_ENGINES + NUM_ROAD_ENGINES + NUM_SHIP_ENGINES + NUM_AIRCRAFT_ENGINES,
- AIRCRAFT_ENGINES_INDEX = NUM_TRAIN_ENGINES + NUM_ROAD_ENGINES + NUM_SHIP_ENGINES,
- SHIP_ENGINES_INDEX = NUM_TRAIN_ENGINES + NUM_ROAD_ENGINES,
- ROAD_ENGINES_INDEX = NUM_TRAIN_ENGINES,
-};
-
#endif /* ENGINE_TYPE_H */
diff --git a/src/group.h b/src/group.h
index 7bac2b48fa..850a3c5deb 100644
--- a/src/group.h
+++ b/src/group.h
@@ -21,7 +21,7 @@ struct Group : PoolItem {
VehicleTypeByte vehicle_type; ///< Vehicle type of the group
bool replace_protection; ///< If set to true, the global autoreplace have no effect on the group
- uint16 num_engines[TOTAL_NUM_ENGINES]; ///< Caches the number of engines of each type the player owns (no need to save this)
+ uint16 *num_engines; ///< Caches the number of engines of each type the player owns (no need to save this)
Group(PlayerID owner = INVALID_PLAYER);
virtual ~Group();
diff --git a/src/group_cmd.cpp b/src/group_cmd.cpp
index 8696b017e7..43ccbe29f5 100644
--- a/src/group_cmd.cpp
+++ b/src/group_cmd.cpp
@@ -22,6 +22,7 @@
#include "player_func.h"
#include "order_func.h"
#include "oldpool_func.h"
+#include "core/alloc_func.hpp"
#include "table/strings.h"
@@ -50,12 +51,14 @@ DEFINE_OLD_POOL_GENERIC(Group, Group)
Group::Group(PlayerID owner)
{
this->owner = owner;
+ this->num_engines = CallocT(GetEnginePoolSize());
}
Group::~Group()
{
free(this->name);
this->owner = INVALID_PLAYER;
+ free(this->num_engines);
}
bool Group::IsValid() const
diff --git a/src/lang/english.txt b/src/lang/english.txt
index 972666cc36..8d11fe3e03 100644
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -1054,6 +1054,7 @@ STR_CONFIG_PATCHES_FREIGHT_TRAINS :{LTBLUE}Weight
STR_CONFIG_PATCHES_PLANE_SPEED :{LTBLUE}Plane speed factor: {ORANGE}1 / {STRING1}
STR_CONFIG_PATCHES_STOP_ON_TOWN_ROAD :{LTBLUE}Allow drive-through road stops on town owned roads: {ORANGE}{STRING}
STR_CONFIG_PATCHES_ADJACENT_STATIONS :{LTBLUE}Allow building adjacent stations: {ORANGE}{STRING}
+STR_CONFIG_PATCHES_DYNAMIC_ENGINES :{LTBLUE}Enable multiple NewGRF engine sets: {ORANGE}{STRING}
STR_CONFIG_PATCHES_SMALL_AIRPORTS :{LTBLUE}Always allow small airports: {ORANGE}{STRING1}
diff --git a/src/newgrf.cpp b/src/newgrf.cpp
index dee8bae67f..0ef3e81d46 100644
--- a/src/newgrf.cpp
+++ b/src/newgrf.cpp
@@ -10,6 +10,7 @@
#include "debug.h"
#include "fileio.h"
#include "engine_func.h"
+#include "engine_base.h"
#include "spritecache.h"
#include "sprite.h"
#include "newgrf.h"
@@ -45,6 +46,7 @@
#include "player_base.h"
#include "settings_type.h"
#include "map_func.h"
+#include