# HG changeset patch # User rubidium # Date 2011-01-18 21:30:59 # Node ID 192110abe258d5ddc9bd4ffb0d2291f7c6a66711 # Parent 1ed01cf3929b0b9d2dc8482796344d88c5fca3fd (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 diff --git a/src/engine.cpp b/src/engine.cpp --- a/src/engine.cpp +++ b/src/engine.cpp @@ -44,6 +44,11 @@ EngineOverrideManager _engine_mngr; */ 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 @@ void SetupEngines() 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 @@ void StartupEngines() 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 @@ static void AcceptEnginePreview(EngineID 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 @@ static CompanyID GetBestCompany(uint8 pp /** 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 @@ static void NewVehicleAvailable(Engine * /* 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); diff --git a/src/newgrf.cpp b/src/newgrf.cpp --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -3209,6 +3209,7 @@ static ChangeInfoResult RailTypeChangeIn 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 @@ static ChangeInfoResult RailTypeChangeIn 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 @@ static ChangeInfoResult RailTypeChangeIn 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 @@ static ChangeInfoResult RailTypeReserveI 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 @@ static ChangeInfoResult RailTypeReserveI buf->ReadByte(); break; + case 0x17: // Introduction date + buf->ReadDWord(); + break; + default: ret = CIR_UNKNOWN; break; diff --git a/src/rail.cpp b/src/rail.cpp --- a/src/rail.cpp +++ b/src/rail.cpp @@ -192,6 +192,40 @@ RailType GetBestRailtype(const CompanyID 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 @@ RailTypes GetCompanyRailtypes(CompanyID } } - return rts; + return AddDateIntroducedRailTypes(rts, _date); } RailType GetRailTypeByLabel(RailTypeLabel label) diff --git a/src/rail.h b/src/rail.h --- 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 @@ struct RailtypeInfo { 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 @@ bool ValParamRailtype(const RailType rai */ 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. diff --git a/src/table/railtypes.h b/src/table/railtypes.h --- a/src/table/railtypes.h +++ b/src/table/railtypes.h @@ -95,6 +95,12 @@ static const RailtypeInfo _original_rail /* 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 @@ static const RailtypeInfo _original_rail /* 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 @@ static const RailtypeInfo _original_rail /* 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 @@ static const RailtypeInfo _original_rail /* map colour */ 0x0A, + /* introduction date */ + INVALID_DATE, + + /* railtypes required for this to be introduced */ + RAILTYPES_NONE, + /* introduction rail types */ RAILTYPES_MAGLEV, diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -703,6 +703,9 @@ static CallBackFunction ToolbarBuildRail 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++) {