diff --git a/docs/newgrf-additions-nml.html b/docs/newgrf-additions-nml.html index b0889c076f..dd70450c73 100644 --- a/docs/newgrf-additions-nml.html +++ b/docs/newgrf-additions-nml.html @@ -178,6 +178,19 @@ + roadtype_collision_modeROADTYPE_COLLISION_MODE_XXX + + Sets the road vehicle collision mode for road vehicles of this road type. +
+
NORMAL
+
Normal road vehicle collision rules (this is the default)
+
NONE
+
Do not collide at all with other road vehicles
+
ELEVATED
+
Collide only with other elevated road vehicles
+
+ +

Tramtype properties

@@ -192,6 +205,19 @@ + + +
tramtype_collision_modeTRAMTYPE_COLLISION_MODE_XXX + Sets the road vehicle collision mode for road vehicles of this tram type. +
+
NORMAL
+
Normal road vehicle collision rules (this is the default)
+
NONE
+
Do not collide at all with other road vehicles
+
ELEVATED
+
Collide only with other elevated road vehicles
+
+

Object IDs

diff --git a/docs/newgrf-additions.html b/docs/newgrf-additions.html index af29569eb1..2216d80fbf 100644 --- a/docs/newgrf-additions.html +++ b/docs/newgrf-additions.html @@ -330,6 +330,18 @@

This is indicated by the feature name: action0_roadtype_extra_flags, version 1

+

Road vehicle collision mode (mappable property: roadtype_collision_mode)

+

This property sets the road vehicle collision mode for road vehicles of this road/tram type.
+ The property length is 1 byte. The format is: + + + + + +
ValueMeaning
0Normal: Normal road vehicle collision rules (this is the default)
1None: Do not collide at all with other road vehicles
2Elevated: Collide only with other elevated road vehicles
+ Unknown values are ignored. More values may be added in future. +

+

This is indicated by the feature name: action0_roadtype_collision_mode, version 1


Action 0 - Global Settings

Extra station names (mappable property: global_extra_station_names)

diff --git a/src/newgrf.cpp b/src/newgrf.cpp index d5cd8e46aa..ce4cd1a323 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -4813,6 +4813,13 @@ static ChangeInfoResult RoadTypeChangeInfo(uint id, int numinfo, int prop, const rti->extra_flags = (RoadTypeExtraFlags)buf->ReadByte(); break; + case A0RPI_ROADTYPE_COLLISION_MODE: { + if (MappedPropertyLengthMismatch(buf, 1, mapping_entry)) break; + uint8 collision_mode = buf->ReadByte(); + if (collision_mode < RTCM_END) rti->collision_mode = (RoadTypeCollisionMode)collision_mode; + break; + } + default: ret = HandleAction0PropertyDefault(buf, prop); break; @@ -4906,6 +4913,10 @@ static ChangeInfoResult RoadTypeReserveInfo(uint id, int numinfo, int prop, cons buf->Skip(buf->ReadExtendedByte()); break; + case A0RPI_ROADTYPE_COLLISION_MODE: + buf->Skip(buf->ReadExtendedByte()); + break; + default: ret = HandleAction0PropertyDefault(buf, prop); break; @@ -11427,6 +11438,7 @@ static void AfterLoadGRFs() /* Set up custom rail types */ InitRailTypes(); InitRoadTypes(); + InitRoadTypesCaches(); for (Engine *e : Engine::IterateType(VEH_ROAD)) { if (_gted[e->index].rv_max_speed != 0) { diff --git a/src/newgrf_extension.cpp b/src/newgrf_extension.cpp index b26d8e90c5..92803c7c31 100644 --- a/src/newgrf_extension.cpp +++ b/src/newgrf_extension.cpp @@ -39,6 +39,7 @@ extern const GRFFeatureInfo _grf_feature_list[] = { GRFFeatureInfo("action0_railtype_recolour", 1), GRFFeatureInfo("action0_railtype_extra_aspects", 1), GRFFeatureInfo("action0_roadtype_extra_flags", 1), + GRFFeatureInfo("action0_roadtype_collision_mode", 1), GRFFeatureInfo("varaction2_railtype_signal_context", 1), GRFFeatureInfo("action0_global_extra_station_names", 2), GRFFeatureInfo("action0_global_default_object_generate_amount", 1), @@ -83,7 +84,9 @@ extern const GRFPropertyMapDefinition _grf_action0_remappable_properties[] = { GRFPropertyMapDefinition(GSF_RAILTYPES, A0RPI_RAILTYPE_ENABLE_SIGNAL_RECOLOUR, "railtype_enable_signal_recolour"), GRFPropertyMapDefinition(GSF_RAILTYPES, A0RPI_RAILTYPE_EXTRA_ASPECTS, "railtype_extra_aspects"), GRFPropertyMapDefinition(GSF_ROADTYPES, A0RPI_ROADTYPE_EXTRA_FLAGS, "roadtype_extra_flags"), + GRFPropertyMapDefinition(GSF_ROADTYPES, A0RPI_ROADTYPE_COLLISION_MODE, "roadtype_collision_mode"), GRFPropertyMapDefinition(GSF_TRAMTYPES, A0RPI_ROADTYPE_EXTRA_FLAGS, "roadtype_extra_flags"), + GRFPropertyMapDefinition(GSF_TRAMTYPES, A0RPI_ROADTYPE_COLLISION_MODE, "roadtype_collision_mode"), GRFPropertyMapDefinition(GSF_GLOBALVAR, A0RPI_GLOBALVAR_EXTRA_STATION_NAMES, "global_extra_station_names"), GRFPropertyMapDefinition(GSF_GLOBALVAR, A0RPI_GLOBALVAR_EXTRA_STATION_NAMES_PROBABILITY, "global_extra_station_names_probability"), GRFPropertyMapDefinition(GSF_GLOBALVAR, A0RPI_GLOBALVAR_LIGHTHOUSE_GENERATE_AMOUNT, "global_lighthouse_generate_amount"), diff --git a/src/newgrf_extension.h b/src/newgrf_extension.h index dd1e6c2184..bb89fdcf79 100644 --- a/src/newgrf_extension.h +++ b/src/newgrf_extension.h @@ -26,6 +26,7 @@ enum Action0RemapPropertyIds { A0RPI_RAILTYPE_ENABLE_SIGNAL_RECOLOUR, A0RPI_RAILTYPE_EXTRA_ASPECTS, A0RPI_ROADTYPE_EXTRA_FLAGS, + A0RPI_ROADTYPE_COLLISION_MODE, A0RPI_GLOBALVAR_EXTRA_STATION_NAMES, A0RPI_GLOBALVAR_EXTRA_STATION_NAMES_PROBABILITY, A0RPI_GLOBALVAR_LIGHTHOUSE_GENERATE_AMOUNT, diff --git a/src/road.h b/src/road.h index a64ca2e9b6..81b7438072 100644 --- a/src/road.h +++ b/src/road.h @@ -62,6 +62,14 @@ enum RoadTypeExtraFlags { }; DECLARE_ENUM_AS_BIT_SET(RoadTypeExtraFlags) +enum RoadTypeCollisionMode : uint8 { + RTCM_NORMAL = 0, + RTCM_NONE, + RTCM_ELEVATED, + + RTCM_END, +}; + struct SpriteGroup; /** Sprite groups for a roadtype. */ @@ -140,6 +148,11 @@ public: */ RoadTypeExtraFlags extra_flags; + /** + * Collision mode + */ + RoadTypeCollisionMode collision_mode; + /** * Cost multiplier for building this road type */ @@ -316,10 +329,12 @@ RoadType GetRoadTypeByLabel(RoadTypeLabel label, bool allow_alternate_labels = t void ResetRoadTypes(); void InitRoadTypes(); +void InitRoadTypesCaches(); RoadType AllocateRoadType(RoadTypeLabel label, RoadTramType rtt); bool HasAnyRoadTypesAvail(CompanyID company, RoadTramType rtt); extern std::vector _sorted_roadtypes; extern RoadTypes _roadtypes_hidden_mask; +extern std::array _collision_mode_roadtypes; #endif /* ROAD_H */ diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index 7a606d17ab..dc30d09011 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -51,6 +51,7 @@ typedef std::vector RoadVehicleList; RoadTypeInfo _roadtypes[ROADTYPE_END]; std::vector _sorted_roadtypes; RoadTypes _roadtypes_hidden_mask; +std::array _collision_mode_roadtypes; /** * Bitmap of road/tram types. @@ -72,7 +73,7 @@ void ResetRoadTypes() { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, {}, {}, 0, {}, {} }, - ROADTYPES_NONE, ROTFB_NONE, RXTFB_NONE, 0, 0, 0, 0, + ROADTYPES_NONE, ROTFB_NONE, RXTFB_NONE, RTCM_NORMAL, 0, 0, 0, 0, RoadTypeLabelList(), 0, 0, ROADTYPES_NONE, ROADTYPES_NONE, 0, {}, {} }; for (; i < lengthof(_roadtypes); i++) _roadtypes[i] = empty_roadtype; @@ -134,6 +135,16 @@ void InitRoadTypes() std::sort(_sorted_roadtypes.begin(), _sorted_roadtypes.end(), CompareRoadTypes); } +void InitRoadTypesCaches() +{ + std::fill(_collision_mode_roadtypes.begin(), _collision_mode_roadtypes.end(), ROADTYPES_NONE); + + for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) { + const RoadTypeInfo &rti = _roadtypes[rt]; + SetBit(_collision_mode_roadtypes[rti.collision_mode], rt); + } +} + /** * Allocate a new road type label */ @@ -149,6 +160,7 @@ RoadType AllocateRoadType(RoadTypeLabel label, RoadTramType rtt) rti->alternate_labels.clear(); rti->flags = ROTFB_NONE; rti->extra_flags = RXTFB_NONE; + rti->collision_mode = RTCM_NORMAL; rti->introduction_date = INVALID_DATE; /* Make us compatible with ourself. */ diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index 75cf328b2d..c98f196849 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -681,6 +681,7 @@ struct RoadVehFindData { Vehicle *best; uint best_diff; Direction dir; + RoadTypeCollisionMode collision_mode; }; static Vehicle *EnumCheckRoadVehClose(Vehicle *v, void *data) @@ -697,6 +698,7 @@ static Vehicle *EnumCheckRoadVehClose(Vehicle *v, void *data) abs(v->z_pos - rvf->veh->z_pos) < 6 && v->direction == rvf->dir && rvf->veh->First() != v->First() && + HasBit(_collision_mode_roadtypes[rvf->collision_mode], RoadVehicle::From(v)->roadtype) && (dist_x[v->direction] >= 0 || (x_diff > dist_x[v->direction] && x_diff <= 0)) && (dist_x[v->direction] <= 0 || (x_diff < dist_x[v->direction] && x_diff >= 0)) && (dist_y[v->direction] >= 0 || (y_diff > dist_y[v->direction] && y_diff <= 0)) && @@ -714,16 +716,19 @@ static Vehicle *EnumCheckRoadVehClose(Vehicle *v, void *data) static RoadVehicle *RoadVehFindCloseTo(RoadVehicle *v, int x, int y, Direction dir, bool update_blocked_ctr = true) { - RoadVehFindData rvf; - RoadVehicle *front = v->First(); + RoadTypeCollisionMode collision_mode = GetRoadTypeInfo(v->roadtype)->collision_mode; + if (collision_mode == RTCM_NONE) return nullptr; + RoadVehicle *front = v->First(); if (front->reverse_ctr != 0) return nullptr; + RoadVehFindData rvf; rvf.x = x; rvf.y = y; rvf.dir = dir; rvf.veh = v; rvf.best_diff = UINT_MAX; + rvf.collision_mode = collision_mode; if (front->state == RVSB_WORMHOLE) { FindVehicleOnPos(v->tile, VEH_ROAD, &rvf, EnumCheckRoadVehClose); @@ -741,7 +746,7 @@ static RoadVehicle *RoadVehFindCloseTo(RoadVehicle *v, int x, int y, Direction d return nullptr; } - if (update_blocked_ctr && ++front->blocked_ctr > 1480 && (!_settings_game.vehicle.roadveh_cant_quantum_tunnel)) return nullptr; + if (update_blocked_ctr && ++front->blocked_ctr > 1480 && (!_settings_game.vehicle.roadveh_cant_quantum_tunnel)) return nullptr; RoadVehicle *rv = RoadVehicle::From(rvf.best); if (rv != nullptr && front->IsRoadVehicleOnLevelCrossing() && (rv->First()->cur_speed == 0 || rv->First()->IsRoadVehicleStopped())) return nullptr; @@ -845,6 +850,7 @@ struct OvertakeData { Trackdir trackdir; int tunnelbridge_min; int tunnelbridge_max; + RoadTypeCollisionMode collision_mode; }; static Vehicle *EnumFindVehBlockingOvertake(Vehicle *v, void *data) @@ -852,6 +858,7 @@ static Vehicle *EnumFindVehBlockingOvertake(Vehicle *v, void *data) const OvertakeData *od = (OvertakeData*)data; if (v->First() == od->u || v->First() == od->v) return nullptr; + if (!HasBit(_collision_mode_roadtypes[od->collision_mode], RoadVehicle::From(v)->roadtype)) return nullptr; if (RoadVehicle::From(v)->overtaking != 0 || v->direction != od->v->direction) return v; /* Check if other vehicle is behind */ @@ -896,6 +903,7 @@ static Vehicle *EnumFindVehBlockingOvertakeBehind(Vehicle *v, void *data) const OvertakeData *od = (OvertakeData*)data; if (v->First() == od->u || v->First() == od->v) return nullptr; + if (!HasBit(_collision_mode_roadtypes[od->collision_mode], RoadVehicle::From(v)->roadtype)) return nullptr; if (RoadVehicle::From(v)->overtaking != 0 && TileVirtXY(v->x_pos, v->y_pos) == od->tile) return v; return nullptr; } @@ -1040,6 +1048,7 @@ static void RoadVehCheckOvertake(RoadVehicle *v, RoadVehicle *u) od.v = v; od.u = u; od.trackdir = DiagDirToDiagTrackdir(DirToDiagDir(v->direction)); + od.collision_mode = GetRoadTypeInfo(v->roadtype)->collision_mode; /* Are the current and the next tile suitable for overtaking? * - Does the track continue along od.trackdir @@ -1447,6 +1456,7 @@ struct FinishOvertakeData { int min_coord; int max_coord; uint8 not_road_pos; + RoadTypeCollisionMode collision_mode; }; static Vehicle *EnumFindVehBlockingFinishOvertake(Vehicle *v, void *data) @@ -1454,6 +1464,7 @@ static Vehicle *EnumFindVehBlockingFinishOvertake(Vehicle *v, void *data) const FinishOvertakeData *od = (FinishOvertakeData*)data; if (v->First() == od->v) return nullptr; + if (!HasBit(_collision_mode_roadtypes[od->collision_mode], RoadVehicle::From(v)->roadtype)) return nullptr; /* Check if other vehicle is behind */ switch (DirToDiagDir(v->direction)) { @@ -1484,6 +1495,8 @@ static void RoadVehCheckFinishOvertake(RoadVehicle *v) FinishOvertakeData od; od.direction = v->direction; od.v = v; + od.collision_mode = GetRoadTypeInfo(v->roadtype)->collision_mode; + const RoadVehicle *last = v->Last(); const int front_margin = 10; const int back_margin = 10; diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index c0b08961b3..d3edc4655b 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -4270,6 +4270,8 @@ void ReloadNewGRFData() UpdateExtraAspectsVariable(); + InitRoadTypesCaches(); + ReInitAllWindows(false); /* Update company statistics. */ diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index 99f978ba6d..72bac726f1 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -1795,6 +1795,8 @@ class NIHRoadType : public NIHelper { HasBit(rti->extra_flags, RXTF_NOT_AVAILABLE_AI_GS) ? 's' : '-', HasBit(rti->extra_flags, RXTF_NO_TOWN_MODIFICATION) ? 't' : '-'); output.print(buffer); + seprintf(buffer, lastof(buffer), " Collision mode: %u", rti->collision_mode); + output.print(buffer); seprintf(buffer, lastof(buffer), " Powered: 0x" OTTD_PRINTFHEX64, rti->powered_roadtypes); output.print(buffer); PrintTypeLabels(buffer, lastof(buffer), rti->label, (const uint32*) rti->alternate_labels.data(), rti->alternate_labels.size(), output.print); diff --git a/src/table/roadtypes.h b/src/table/roadtypes.h index c98f55a2e9..a582d05db1 100644 --- a/src/table/roadtypes.h +++ b/src/table/roadtypes.h @@ -66,6 +66,9 @@ static const RoadTypeInfo _original_roadtypes[] = { /* extra flags */ RXTFB_NONE, + /* collision mode */ + RTCM_NORMAL, + /* cost multiplier */ 8, @@ -149,6 +152,9 @@ static const RoadTypeInfo _original_roadtypes[] = { /* extra flags */ RXTFB_NONE, + /* collision mode */ + RTCM_NORMAL, + /* cost multiplier */ 16,