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_mode | ROADTYPE_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
+
+ |
+
@@ -192,6 +205,19 @@
+ tramtype_collision_mode | TRAMTYPE_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
+
+ |
+
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:
+
+ Value | Meaning |
+ 0 | Normal: Normal road vehicle collision rules (this is the default) |
+ 1 | None: Do not collide at all with other road vehicles |
+ 2 | Elevated: 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
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,