diff options
Diffstat (limited to 'src/newgrf.cpp')
-rw-r--r-- | src/newgrf.cpp | 372 |
1 files changed, 369 insertions, 3 deletions
diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 759c556a7..82279ab99 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -49,6 +49,7 @@ #include "vehicle_func.h" #include "language.h" #include "vehicle_base.h" +#include "road.h" #include "table/strings.h" #include "table/build_industry.h" @@ -309,6 +310,7 @@ struct GRFTempEngineData { uint16 cargo_allowed; uint16 cargo_disallowed; RailTypeLabel railtypelabel; + uint8 roadtramtype; const GRFFile *defaultcargo_grf; ///< GRF defining the cargo translation table to use if the default cargo is the 'first refittable'. Refittability refittability; ///< Did the newgrf set any refittability property? If not, default refittability will be applied. bool prop27_set; ///< Did the NewGRF set property 27 (misc flags)? @@ -1345,6 +1347,12 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop RoadVehicleInfo *rvi = &e->u.road; switch (prop) { + case 0x05: // Road/tram type + /* RoadTypeLabel is looked up later after the engine's road/tram + * flag is set, however 0 means the value has not been set. */ + _gted[e->index].roadtramtype = buf->ReadByte() + 1; + break; + case 0x08: // Speed (1 unit is 0.5 kmh) rvi->max_speed = buf->ReadByte(); break; @@ -2615,6 +2623,12 @@ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, By case 0x12: // Rail type translation table; loading during both reservation and activation stage (in case it is selected depending on defined railtypes) return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->railtype_list, "Rail type"); + case 0x16: // Road type translation table; loading during both reservation and activation stage (in case it is selected depending on defined railtypes) + return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->roadtype_list, "Road type"); + + case 0x17: // Tram type translation table; loading during both reservation and activation stage (in case it is selected depending on defined railtypes) + return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->tramtype_list, "Tram type"); + default: break; } @@ -2830,6 +2844,12 @@ static ChangeInfoResult GlobalVarReserveInfo(uint gvid, int numinfo, int prop, B case 0x12: // Rail type translation table; loading during both reservation and activation stage (in case it is selected depending on defined railtypes) return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->railtype_list, "Rail type"); + case 0x16: // Road type translation table; loading during both reservation and activation stage (in case it is selected depending on defined roadtypes) + return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->roadtype_list, "Road type"); + + case 0x17: // Tram type translation table; loading during both reservation and activation stage (in case it is selected depending on defined tramtypes) + return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->tramtype_list, "Tram type"); + default: break; } @@ -4368,6 +4388,228 @@ static ChangeInfoResult RailTypeReserveInfo(uint id, int numinfo, int prop, Byte return ret; } +/** + * Define properties for roadtypes + * @param id ID of the roadtype. + * @param numinfo Number of subsequent IDs to change the property for. + * @param prop The property to change. + * @param buf The property value. + * @return ChangeInfoResult. + */ +static ChangeInfoResult RoadTypeChangeInfo(uint id, int numinfo, int prop, ByteReader *buf, RoadTramType rtt) +{ + ChangeInfoResult ret = CIR_SUCCESS; + + extern RoadTypeInfo _roadtypes[ROADTYPE_END]; + RoadType *type_map = (rtt == RTT_TRAM) ? _cur.grffile->tramtype_map : _cur.grffile->roadtype_map; + + if (id + numinfo > ROADTYPE_END) { + grfmsg(1, "RoadTypeChangeInfo: Road type %u is invalid, max %u, ignoring", id + numinfo, ROADTYPE_END); + return CIR_INVALID_ID; + } + + for (int i = 0; i < numinfo; i++) { + RoadType rt = type_map[id + i]; + if (rt == INVALID_ROADTYPE) return CIR_INVALID_ID; + + RoadTypeInfo *rti = &_roadtypes[rt]; + + switch (prop) { + case 0x08: // Label of road type + /* Skipped here as this is loaded during reservation stage. */ + buf->ReadDWord(); + break; + + case 0x09: { // Toolbar caption of roadtype (sets name as well for backwards compatibility for grf ver < 8) + uint16 str = buf->ReadWord(); + AddStringForMapping(str, &rti->strings.toolbar_caption); + break; + } + + case 0x0A: // Menu text of roadtype + AddStringForMapping(buf->ReadWord(), &rti->strings.menu_text); + break; + + case 0x0B: // Build window caption + AddStringForMapping(buf->ReadWord(), &rti->strings.build_caption); + break; + + case 0x0C: // Autoreplace text + AddStringForMapping(buf->ReadWord(), &rti->strings.replace_text); + break; + + case 0x0D: // New engine text + AddStringForMapping(buf->ReadWord(), &rti->strings.new_engine); + break; + + case 0x0F: // Powered roadtype list + case 0x18: // Roadtype list required for date introduction + case 0x19: { // Introduced roadtype list + /* Road type compatibility bits are added to the existing bits + * to allow multiple GRFs to modify compatibility with the + * default road types. */ + int n = buf->ReadByte(); + for (int j = 0; j != n; j++) { + RoadTypeLabel label = buf->ReadDWord(); + RoadType rt = GetRoadTypeByLabel(BSWAP32(label), false); + if (rt != INVALID_ROADTYPE) { + switch (prop) { + case 0x0F: SetBit(rti->powered_roadtypes, rt); break; + case 0x18: SetBit(rti->introduction_required_roadtypes, rt); break; + case 0x19: SetBit(rti->introduces_roadtypes, rt); break; + } + } + } + break; + } + + case 0x10: // Road Type flags + rti->flags = (RoadTypeFlags)buf->ReadByte(); + break; + + case 0x13: // Construction cost factor + rti->cost_multiplier = buf->ReadWord(); + break; + + case 0x14: // Speed limit + rti->max_speed = buf->ReadWord(); + break; + + case 0x16: // Map colour + rti->map_colour = buf->ReadByte(); + break; + + case 0x17: // Introduction date + rti->introduction_date = buf->ReadDWord(); + break; + + case 0x1A: // Sort order + rti->sorting_order = buf->ReadByte(); + break; + + case 0x1B: // Name of roadtype + AddStringForMapping(buf->ReadWord(), &rti->strings.name); + break; + + case 0x1C: // Maintenance cost factor + rti->maintenance_multiplier = buf->ReadWord(); + break; + + case 0x1D: // Alternate road type label list + /* Skipped here as this is loaded during reservation stage. */ + for (int j = buf->ReadByte(); j != 0; j--) buf->ReadDWord(); + break; + + default: + ret = CIR_UNKNOWN; + break; + } + } + + return ret; +} + +static ChangeInfoResult RoadTypeChangeInfo(uint id, int numinfo, int prop, ByteReader *buf) +{ + return RoadTypeChangeInfo(id, numinfo, prop, buf, RTT_ROAD); +} + +static ChangeInfoResult TramTypeChangeInfo(uint id, int numinfo, int prop, ByteReader *buf) +{ + return RoadTypeChangeInfo(id, numinfo, prop, buf, RTT_TRAM); +} + + +static ChangeInfoResult RoadTypeReserveInfo(uint id, int numinfo, int prop, ByteReader *buf, RoadTramType rtt) +{ + ChangeInfoResult ret = CIR_SUCCESS; + + extern RoadTypeInfo _roadtypes[ROADTYPE_END]; + RoadType *type_map = (rtt == RTT_TRAM) ? _cur.grffile->tramtype_map : _cur.grffile->roadtype_map; + + if (id + numinfo > ROADTYPE_END) { + grfmsg(1, "RoadTypeReserveInfo: Road type %u is invalid, max %u, ignoring", id + numinfo, ROADTYPE_END); + return CIR_INVALID_ID; + } + + for (int i = 0; i < numinfo; i++) { + switch (prop) { + case 0x08: { // Label of road type + RoadTypeLabel rtl = buf->ReadDWord(); + rtl = BSWAP32(rtl); + + RoadType rt = GetRoadTypeByLabel(rtl, false); + if (rt == INVALID_ROADTYPE) { + /* Set up new road type */ + rt = AllocateRoadType(rtl, rtt); + } else if (GetRoadTramType(rt) != rtt) { + grfmsg(1, "RoadTypeReserveInfo: Road type %u is invalid type (road/tram), ignoring", id + numinfo); + return CIR_INVALID_ID; + } + + type_map[id + i] = rt; + break; + } + case 0x09: // Toolbar caption of roadtype + case 0x0A: // Menu text + case 0x0B: // Build window caption + case 0x0C: // Autoreplace text + case 0x0D: // New loco + case 0x13: // Construction cost + case 0x14: // Speed limit + case 0x1B: // Name of roadtype + case 0x1C: // Maintenance cost factor + buf->ReadWord(); + break; + + case 0x1D: // Alternate road type label list + if (type_map[id + i] != INVALID_ROADTYPE) { + int n = buf->ReadByte(); + for (int j = 0; j != n; j++) { + _roadtypes[type_map[id + i]].alternate_labels.push_back(BSWAP32(buf->ReadDWord())); + } + break; + } + grfmsg(1, "RoadTypeReserveInfo: Ignoring property 1D for road type %u because no label was set", id + i); + /* FALL THROUGH */ + + case 0x0F: // Powered roadtype list + case 0x18: // Roadtype list required for date introduction + case 0x19: // Introduced roadtype list + for (int j = buf->ReadByte(); j != 0; j--) buf->ReadDWord(); + break; + + case 0x10: // Road Type flags + case 0x12: // Station graphic + case 0x15: // Acceleration model + case 0x16: // Map colour + case 0x1A: // Sort order + buf->ReadByte(); + break; + + case 0x17: // Introduction date + buf->ReadDWord(); + break; + + default: + ret = CIR_UNKNOWN; + break; + } + } + + return ret; +} + +static ChangeInfoResult RoadTypeReserveInfo(uint id, int numinfo, int prop, ByteReader *buf) +{ + return RoadTypeReserveInfo(id, numinfo, prop, buf, RTT_ROAD); +} + +static ChangeInfoResult TramTypeReserveInfo(uint id, int numinfo, int prop, ByteReader *buf) +{ + return RoadTypeReserveInfo(id, numinfo, prop, buf, RTT_TRAM); +} + static ChangeInfoResult AirportTilesChangeInfo(uint airtid, int numinfo, int prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; @@ -4520,6 +4762,8 @@ static void FeatureChangeInfo(ByteReader *buf) /* GSF_OBJECTS */ ObjectChangeInfo, /* GSF_RAILTYPES */ RailTypeChangeInfo, /* GSF_AIRPORTTILES */ AirportTilesChangeInfo, + /* GSF_ROADTYPES */ RoadTypeChangeInfo, + /* GSF_TRAMTYPES */ TramTypeChangeInfo, }; uint8 feature = buf->ReadByte(); @@ -4593,7 +4837,7 @@ static void ReserveChangeInfo(ByteReader *buf) { uint8 feature = buf->ReadByte(); - if (feature != GSF_CARGOES && feature != GSF_GLOBALVAR && feature != GSF_RAILTYPES) return; + if (feature != GSF_CARGOES && feature != GSF_GLOBALVAR && feature != GSF_RAILTYPES && feature != GSF_ROADTYPES && feature != GSF_TRAMTYPES) return; uint8 numprops = buf->ReadByte(); uint8 numinfo = buf->ReadByte(); @@ -4616,6 +4860,14 @@ static void ReserveChangeInfo(ByteReader *buf) case GSF_RAILTYPES: cir = RailTypeReserveInfo(index, numinfo, prop, buf); break; + + case GSF_ROADTYPES: + cir = RoadTypeReserveInfo(index, numinfo, prop, buf); + break; + + case GSF_TRAMTYPES: + cir = TramTypeReserveInfo(index, numinfo, prop, buf); + break; } if (HandleChangeInfoResult("ReserveChangeInfo", cir, feature, prop)) return; @@ -4928,6 +5180,8 @@ static void NewSpriteGroup(ByteReader *buf) case GSF_CARGOES: case GSF_AIRPORTS: case GSF_RAILTYPES: + case GSF_ROADTYPES: + case GSF_TRAMTYPES: { byte num_loaded = type; byte num_loading = buf->ReadByte(); @@ -5505,6 +5759,39 @@ static void RailTypeMapSpriteGroup(ByteReader *buf, uint8 idcount) buf->ReadWord(); } +static void RoadTypeMapSpriteGroup(ByteReader *buf, uint8 idcount, RoadTramType rtt) +{ + RoadType *type_map = (rtt == RTT_TRAM) ? _cur.grffile->tramtype_map : _cur.grffile->roadtype_map; + + uint8 *roadtypes = AllocaM(uint8, idcount); + for (uint i = 0; i < idcount; i++) { + uint8 id = buf->ReadByte(); + roadtypes[i] = id < ROADTYPE_END ? type_map[id] : INVALID_ROADTYPE; + } + + uint8 cidcount = buf->ReadByte(); + for (uint c = 0; c < cidcount; c++) { + uint8 ctype = buf->ReadByte(); + uint16 groupid = buf->ReadWord(); + if (!IsValidGroupID(groupid, "RoadTypeMapSpriteGroup")) continue; + + if (ctype >= ROTSG_END) continue; + + extern RoadTypeInfo _roadtypes[ROADTYPE_END]; + for (uint i = 0; i < idcount; i++) { + if (roadtypes[i] != INVALID_ROADTYPE) { + RoadTypeInfo *rti = &_roadtypes[roadtypes[i]]; + + rti->grffile[ctype] = _cur.grffile; + rti->group[ctype] = _cur.spritegroups[groupid]; + } + } + } + + /* Roadtypes do not use the default group. */ + buf->ReadWord(); +} + static void AirportMapSpriteGroup(ByteReader *buf, uint8 idcount) { uint8 *airports = AllocaM(uint8, idcount); @@ -5655,6 +5942,14 @@ static void FeatureMapSpriteGroup(ByteReader *buf) RailTypeMapSpriteGroup(buf, idcount); break; + case GSF_ROADTYPES: + RoadTypeMapSpriteGroup(buf, idcount, RTT_ROAD); + break; + + case GSF_TRAMTYPES: + RoadTypeMapSpriteGroup(buf, idcount, RTT_TRAM); + break; + case GSF_AIRPORTTILES: AirportTileMapSpriteGroup(buf, idcount); return; @@ -5917,13 +6212,20 @@ static void GraphicsNew(ByteReader *buf) /* Load <num> sprites starting from <replace>, then skip <skip_num> sprites. */ grfmsg(2, "GraphicsNew: Replacing sprites %d to %d of %s (type 0x%02X) at SpriteID 0x%04X", offset, offset + num - 1, action5_type->name, type, replace); + if (type == 0x0D) _loaded_newgrf_features.shore = SHORE_REPLACE_ACTION_5; + + if (type == 0x0B) { + static const SpriteID depot_with_track_offset = SPR_TRAMWAY_DEPOT_WITH_TRACK - SPR_TRAMWAY_BASE; + static const SpriteID depot_no_track_offset = SPR_TRAMWAY_DEPOT_NO_TRACK - SPR_TRAMWAY_BASE; + if (offset <= depot_with_track_offset && offset + num > depot_with_track_offset) _loaded_newgrf_features.tram = TRAMWAY_REPLACE_DEPOT_WITH_TRACK; + if (offset <= depot_no_track_offset && offset + num > depot_no_track_offset) _loaded_newgrf_features.tram = TRAMWAY_REPLACE_DEPOT_NO_TRACK; + } + for (; num > 0; num--) { _cur.nfo_line++; LoadNextSprite(replace == 0 ? _cur.spriteid++ : replace++, _cur.file_index, _cur.nfo_line, _cur.grf_container_ver); } - if (type == 0x0D) _loaded_newgrf_features.shore = SHORE_REPLACE_ACTION_5; - _cur.skip_sprites = skip_num; } @@ -6349,6 +6651,14 @@ static void SkipIf(ByteReader *buf) break; case 0x0E: result = GetRailTypeByLabel(BSWAP32(cond_val)) != INVALID_RAILTYPE; break; + case 0x0F: result = GetRoadTypeByLabel(BSWAP32(cond_val)) == INVALID_ROADTYPE; + break; + case 0x10: result = GetRoadTypeByLabel(BSWAP32(cond_val)) != INVALID_ROADTYPE; + break; + case 0x11: result = GetRoadTypeByLabel(BSWAP32(cond_val)) == INVALID_ROADTYPE; + break; + case 0x12: result = GetRoadTypeByLabel(BSWAP32(cond_val)) != INVALID_ROADTYPE; + break; default: grfmsg(1, "SkipIf: Unsupported condition type %02X. Ignoring", condtype); return; } @@ -8269,6 +8579,9 @@ void ResetNewGRFData() /* Reset rail type information */ ResetRailTypes(); + /* Copy/reset original road type info data */ + ResetRoadTypes(); + /* Allocate temporary refit/cargo class data */ _gted = CallocT<GRFTempEngineData>(Engine::GetPoolSize()); @@ -8337,6 +8650,7 @@ void ResetNewGRFData() _loaded_newgrf_features.has_newhouses = false; _loaded_newgrf_features.has_newindustries = false; _loaded_newgrf_features.shore = SHORE_REPLACE_NONE; + _loaded_newgrf_features.tram = TRAMWAY_REPLACE_DEPOT_NONE; /* Clear all GRF overrides */ _grf_id_overrides.clear(); @@ -8424,6 +8738,14 @@ GRFFile::GRFFile(const GRFConfig *config) this->railtype_map[2] = RAILTYPE_MONO; this->railtype_map[3] = RAILTYPE_MAGLEV; + /* Initialise road type map with default road types */ + memset(this->roadtype_map, INVALID_ROADTYPE, sizeof(this->roadtype_map)); + this->roadtype_map[0] = ROADTYPE_ROAD; + + /* Initialise tram type map with default tram types */ + memset(this->tramtype_map, INVALID_ROADTYPE, sizeof(this->tramtype_map)); + this->tramtype_map[0] = ROADTYPE_TRAM; + /* Copy the initial parameter list * 'Uninitialised' parameters are zeroed as that is their default value when dynamically creating them. */ assert_compile(lengthof(this->param) == lengthof(config->param) && lengthof(this->param) == 0x80); @@ -9194,6 +9516,21 @@ static void ActivateOldShore() } /** + * Replocate the old tram depot sprites to the new position, if no new ones were loaded. + */ +static void ActivateOldTramDepot() +{ + if (_loaded_newgrf_features.tram == TRAMWAY_REPLACE_DEPOT_WITH_TRACK) { + DupSprite(SPR_ROAD_DEPOT + 0, SPR_TRAMWAY_DEPOT_NO_TRACK + 0); // use road depot graphics for "no tracks" + DupSprite(SPR_TRAMWAY_DEPOT_WITH_TRACK + 1, SPR_TRAMWAY_DEPOT_NO_TRACK + 1); + DupSprite(SPR_ROAD_DEPOT + 2, SPR_TRAMWAY_DEPOT_NO_TRACK + 2); // use road depot graphics for "no tracks" + DupSprite(SPR_TRAMWAY_DEPOT_WITH_TRACK + 3, SPR_TRAMWAY_DEPOT_NO_TRACK + 3); + DupSprite(SPR_TRAMWAY_DEPOT_WITH_TRACK + 4, SPR_TRAMWAY_DEPOT_NO_TRACK + 4); + DupSprite(SPR_TRAMWAY_DEPOT_WITH_TRACK + 5, SPR_TRAMWAY_DEPOT_NO_TRACK + 5); + } +} + +/** * Decide whether price base multipliers of grfs shall apply globally or only to the grf specifying them */ static void FinalisePriceBaseMultipliers() @@ -9371,8 +9708,12 @@ static void AfterLoadGRFs() /* Load old shore sprites in new position, if they were replaced by ActionA */ ActivateOldShore(); + /* Load old tram depot sprites in new position, if no new ones are present */ + ActivateOldTramDepot(); + /* Set up custom rail types */ InitRailTypes(); + InitRoadTypes(); Engine *e; FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { @@ -9380,6 +9721,31 @@ static void AfterLoadGRFs() /* Set RV maximum speed from the mph/0.8 unit value */ e->u.road.max_speed = _gted[e->index].rv_max_speed * 4; } + + RoadTramType rtt = HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? RTT_TRAM : RTT_ROAD; + + const GRFFile *file = e->GetGRF(); + if (file == nullptr || _gted[e->index].roadtramtype == 0) { + e->u.road.roadtype = (rtt == RTT_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD; + continue; + } + + /* Remove +1 offset. */ + _gted[e->index].roadtramtype--; + + const std::vector<RoadTypeLabel> *list = (rtt == RTT_TRAM) ? &file->tramtype_list : &file->roadtype_list; + if (_gted[e->index].roadtramtype < list->size()) + { + RoadTypeLabel rtl = (*list)[_gted[e->index].roadtramtype]; + RoadType rt = GetRoadTypeByLabel(rtl); + if (rt != INVALID_ROADTYPE && GetRoadTramType(rt) == rtt) { + e->u.road.roadtype = rt; + continue; + } + } + + /* Road type is not available, so disable this engine */ + e->info.climates = 0; } FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { |