changeset 17105:a804b91f3a3e draft

(svn r21842) -Feature [FS#4393]: [NewGRF] Introduction dates/required types for rail types; e.g. introduce a particular rail type in 1960 (or when a vehicle using it is introduced), but also allow limiting its introduction to only happen when the required railtypes are available
author rubidium <rubidium@openttd.org>
date Tue, 18 Jan 2011 21:30:59 +0000
parents f081bf6f0633
children 49e51c1b1b5f
files src/engine.cpp src/newgrf.cpp src/rail.cpp src/rail.h src/table/railtypes.h src/toolbar_gui.cpp
diffstat 6 files changed, 135 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -44,6 +44,11 @@
  */
 static Year _year_engine_aging_stops;
 
+/**
+ * The railtypes that have been or never will be introduced, or
+ * an inverse bitmap of rail types that have to be introduced. */
+static uint16 _introduced_railtypes;
+
 /** Number of engines of each vehicle type in original engine data */
 const uint8 _engine_counts[4] = {
 	lengthof(_orig_rail_vehicle_info),
@@ -474,8 +479,30 @@
 		const Engine *e = new Engine(eid->type, eid->internal_id);
 		assert(e->index == index);
 	}
+
+	_introduced_railtypes = 0;
 }
 
+/**
+ * Check whether the railtypes should be introduced.
+ */
+static void CheckRailIntroduction()
+{
+	/* All railtypes have been introduced. */
+	if (_introduced_railtypes == UINT16_MAX || Company::GetPoolSize() == 0) return;
+
+	/* We need to find the railtypes that are known to all companies. */
+	RailTypes rts = (RailTypes)UINT16_MAX;
+
+	/* We are at, or past the introduction date of the rail. */
+	Company *c;
+	FOR_ALL_COMPANIES(c) {
+		c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes, _date);
+		rts &= c->avail_railtypes;
+	}
+
+	_introduced_railtypes |= rts;
+}
 
 void ShowEnginePreviewWindow(EngineID engine);
 
@@ -602,6 +629,19 @@
 		c->avail_roadtypes = GetCompanyRoadtypes(c->index);
 	}
 
+	/* Rail types that are invalid or never introduced are marked as
+	 * being introduced upon start. That way we can easily check whether
+	 * there is any date related introduction that is still going to
+	 * happen somewhere in the future. */
+	for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
+		const RailtypeInfo *rti = GetRailTypeInfo(rt);
+		if (rti->label != 0 && IsInsideMM(rti->introduction_date, 0, MAX_DAY)) continue;
+
+		SetBit(_introduced_railtypes, rt);
+	}
+
+	CheckRailIntroduction();
+
 	/* Invalidate any open purchase lists */
 	InvalidateWindowClassesData(WC_BUILD_VEHICLE);
 }
@@ -614,7 +654,7 @@
 	SetBit(e->company_avail, company);
 	if (e->type == VEH_TRAIN) {
 		assert(e->u.rail.railtype < RAILTYPE_END);
-		c->avail_railtypes |= GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes;
+		c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes, _date);
 	} else if (e->type == VEH_ROAD) {
 		SetBit(c->avail_roadtypes, HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD);
 	}
@@ -663,6 +703,8 @@
 /** Daily check to offer an exclusive engine preview to the companies. */
 void EnginesDailyLoop()
 {
+	CheckRailIntroduction();
+
 	if (_cur_year >= _year_engine_aging_stops) return;
 
 	Engine *e;
@@ -760,7 +802,7 @@
 		/* maybe make another rail type available */
 		RailType railtype = e->u.rail.railtype;
 		assert(railtype < RAILTYPE_END);
-		FOR_ALL_COMPANIES(c) c->avail_railtypes |= GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes;
+		FOR_ALL_COMPANIES(c) c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes, _date);
 	} else if (e->type == VEH_ROAD) {
 		/* maybe make another road type available */
 		FOR_ALL_COMPANIES(c) SetBit(c->avail_roadtypes, HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD);
--- a/src/newgrf.cpp
+++ b/src/newgrf.cpp
@@ -3209,6 +3209,7 @@
 
 			case 0x0E: // Compatible railtype list
 			case 0x0F: // Powered railtype list
+			case 0x18: // Railtype list required for date introduction
 			case 0x19: // Introduced railtype list
 			{
 				/* Rail type compatibility bits are added to the existing bits
@@ -3222,6 +3223,7 @@
 						switch (prop) {
 							case 0x0E: SetBit(rti->compatible_railtypes, rt);            break;
 							case 0x0F: SetBit(rti->powered_railtypes, rt);               break;
+							case 0x18: SetBit(rti->introduction_required_railtypes, rt); break;
 							case 0x19: SetBit(rti->introduces_railtypes, rt);            break;
 						}
 					}
@@ -3257,6 +3259,10 @@
 				rti->map_colour = MapDOSColour(buf->ReadByte());
 				break;
 
+			case 0x17: // Introduction date
+				rti->introduction_date = buf->ReadDWord();
+				break;
+
 			default:
 				ret = CIR_UNKNOWN;
 				break;
@@ -3304,6 +3310,7 @@
 
 			case 0x0E: // Compatible railtype list
 			case 0x0F: // Powered railtype list
+			case 0x18: // Railtype list required for date introduction
 			case 0x19: // Introduced railtype list
 				for (int j = buf->ReadByte(); j != 0; j--) buf->ReadDWord();
 				break;
@@ -3316,6 +3323,10 @@
 				buf->ReadByte();
 				break;
 
+			case 0x17: // Introduction date
+				buf->ReadDWord();
+				break;
+
 			default:
 				ret = CIR_UNKNOWN;
 				break;
--- a/src/rail.cpp
+++ b/src/rail.cpp
@@ -192,6 +192,40 @@
 	return RAILTYPE_RAIL;
 }
 
+/**
+ * Add the rail types that are to be introduced at the given date.
+ * @param current The currently available railtypes.
+ * @param date    The date for the introduction comparisions.
+ * @return The rail types that should be available when date
+ *         introduced rail types are taken into account as well.
+ */
+RailTypes AddDateIntroducedRailTypes(RailTypes current, Date date)
+{
+	RailTypes rts = current;
+
+	for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
+		const RailtypeInfo *rti = GetRailTypeInfo(rt);
+		/* Unused rail type. */
+		if (rti->label == 0) continue;
+
+		/* Not date introduced. */
+		if (!IsInsideMM(rti->introduction_date, 0, MAX_DAY)) continue;
+
+		/* Not yet introduced at this date. */
+		if (rti->introduction_date > date) continue;
+
+		/* Have we introduced all required railtypes? */
+		RailTypes required = rti->introduction_required_railtypes;
+		if ((rts & required) != required) continue;
+
+		rts |= rti->introduces_railtypes;
+	}
+
+	/* When we added railtypes we need to run this method again; the added
+	 * railtypes might enable more rail types to become introduced. */
+	return rts == current ? rts : AddDateIntroducedRailTypes(rts, date);
+}
+
 RailTypes GetCompanyRailtypes(CompanyID company)
 {
 	RailTypes rts = RAILTYPES_NONE;
@@ -211,7 +245,7 @@
 		}
 	}
 
-	return rts;
+	return AddDateIntroducedRailTypes(rts, _date);
 }
 
 RailType GetRailTypeByLabel(RailTypeLabel label)
--- a/src/rail.h
+++ b/src/rail.h
@@ -19,6 +19,7 @@
 #include "economy_func.h"
 #include "slope_type.h"
 #include "strings_type.h"
+#include "date_type.h"
 
 /** Railtype flags. */
 enum RailTypeFlags {
@@ -217,6 +218,21 @@
 	byte map_colour;
 
 	/**
+	 * Introduction date.
+	 * When #INVALID_DATE or a vehicle using this railtype gets introduced earlier,
+	 * the vehicle's introduction date will be used instead for this railtype.
+	 * The introduction at this date is furthermore limited by the
+	 * #introduction_required_types.
+	 */
+	Date introduction_date;
+
+	/**
+	 * Bitmask of railtypes that are required for this railtype to be introduced
+	 * at a given #introduction_date.
+	 */
+	RailTypes introduction_required_railtypes;
+
+	/**
 	 * Bitmask of which other railtypes are introduced when this railtype is introduced.
 	 */
 	RailTypes introduces_railtypes;
@@ -368,6 +384,8 @@
  */
 RailType GetBestRailtype(const CompanyID company);
 
+RailTypes AddDateIntroducedRailTypes(RailTypes current, Date date);
+
 /**
  * Get the rail types the given company can build.
  * @param c the company to get the rail types for.
--- a/src/table/railtypes.h
+++ b/src/table/railtypes.h
@@ -95,6 +95,12 @@
 		/* map colour */
 		0x0A,
 
+		/* introduction date */
+		INVALID_DATE,
+
+		/* railtypes required for this to be introduced */
+		RAILTYPES_NONE,
+
 		/* introduction rail types */
 		RAILTYPES_RAIL,
 
@@ -181,6 +187,12 @@
 		/* map colour */
 		0x0A,
 
+		/* introduction date */
+		INVALID_DATE,
+
+		/* railtypes required for this to be introduced */
+		RAILTYPES_NONE,
+
 		/* introduction rail types */
 		RAILTYPES_ELECTRIC,
 
@@ -263,6 +275,12 @@
 		/* map colour */
 		0x0A,
 
+		/* introduction date */
+		INVALID_DATE,
+
+		/* railtypes required for this to be introduced */
+		RAILTYPES_NONE,
+
 		/* introduction rail types */
 		RAILTYPES_MONO,
 
@@ -345,6 +363,12 @@
 		/* map colour */
 		0x0A,
 
+		/* introduction date */
+		INVALID_DATE,
+
+		/* railtypes required for this to be introduced */
+		RAILTYPES_NONE,
+
 		/* introduction rail types */
 		RAILTYPES_MAGLEV,
 
--- a/src/toolbar_gui.cpp
+++ b/src/toolbar_gui.cpp
@@ -703,6 +703,9 @@
 		used_railtypes |= GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes;
 	}
 
+	/* Get the date introduced railtypes as well. */
+	used_railtypes = AddDateIntroducedRailTypes(used_railtypes, MAX_DAY);
+
 	const Company *c = Company::Get(_local_company);
 	DropDownList *list = new DropDownList();
 	for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {