diff --git a/src/lang/english.txt b/src/lang/english.txt index 63b87e0b72..14b58a4639 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1261,6 +1261,8 @@ STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD_HELPTEXT :Allow construct STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES :{WHITE}Changing this setting is not possible when there are vehicles STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE :Infrastructure maintenance: {STRING2} STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE_HELPTEXT :When enabled, infrastructure causes maintenance costs. The cost grows over-proportional with the network size, thus affecting bigger companies more than smaller ones +STR_CONFIG_SETTING_SHIP_COLLISION_AVOIDANCE :Ships avoid collisions: {STRING2} +STR_CONFIG_SETTING_SHIP_COLLISION_AVOIDANCE_HELPTEXT :When enabled, ships try to avoid passing through each other. Requires 90° turns to be forbidden. STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS :Airports never expire: {STRING2} STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS_HELPTEXT :Enabling this setting makes each airport type stay available forever after its introduction diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 27d8f6b851..3e59bacc98 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -1668,6 +1668,7 @@ static SettingsContainer &GetSettingsTree() physics->Add(new SettingEntry("vehicle.roadveh_slope_steepness")); physics->Add(new SettingEntry("vehicle.smoke_amount")); physics->Add(new SettingEntry("vehicle.plane_speed")); + physics->Add(new SettingEntry("vehicle.ship_collision_avoidance")); } SettingsPage *routing = vehicles->Add(new SettingsPage(STR_CONFIG_SETTING_VEHICLES_ROUTING)); diff --git a/src/settings_type.h b/src/settings_type.h index f703e95da4..ec121b6298 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -512,6 +512,7 @@ struct VehicleSettings { bool improved_breakdowns; ///< different types, chances and severities of breakdowns bool pay_for_repair; ///< pay for repairing vehicle uint8 repair_cost; ///< cost of repairing vehicle + bool ship_collision_avoidance; ///< ships try to avoid colliding with each other }; /** Settings related to the economy. */ diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index bdbea98572..4ccf1a3539 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -529,6 +529,24 @@ static const byte _ship_subcoord[4][6][3] = { } }; +/* Used to find DiagDirection from tile to next tile if track is followed */ +static const DiagDirection _diagdir_to_next_tile[6][4] = { + { DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_NW }, + { DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_NW }, + { DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_NW, DIAGDIR_SW }, + { DIAGDIR_SE, DIAGDIR_NW, DIAGDIR_NE, DIAGDIR_SW }, + { DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_SE, DIAGDIR_NE }, + { DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_SE, DIAGDIR_NE } +}; + +/** Helper function for collision avoidance. */ +static Vehicle *FindShipOnTile(Vehicle *v, void *data) +{ + if (v->type != VEH_SHIP || v->vehstatus & VS_STOPPED) return NULL; + + return v; +} + static void ShipController(Ship *v) { uint32 r; @@ -621,6 +639,25 @@ static void ShipController(Ship *v) track = ChooseShipTrack(v, gp.new_tile, diagdir, tracks); if (track == INVALID_TRACK) goto reverse_direction; + /* Try to avoid collision and keep distance between each other. */ + if (_settings_game.pf.forbid_90_deg && _settings_game.vehicle.ship_collision_avoidance && DistanceManhattan(v->dest_tile, gp.new_tile) > 3) { + if (HasVehicleOnPos(gp.new_tile, NULL, &FindShipOnTile) || + HasVehicleOnPos(TileAddByDiagDir(gp.new_tile, _diagdir_to_next_tile[track][diagdir]), NULL, &FindShipOnTile)) { + + v->cur_speed /= 4; // Go quarter speed. + + Track old = track; + switch (tracks) { + default: break; + case TRACK_BIT_3WAY_NE: track == TRACK_RIGHT ? track = TRACK_X : track = TRACK_UPPER; break; + case TRACK_BIT_3WAY_SE: track == TRACK_LOWER ? track = TRACK_Y : track = TRACK_RIGHT; break; + case TRACK_BIT_3WAY_SW: track == TRACK_LEFT ? track = TRACK_X : track = TRACK_LOWER; break; + case TRACK_BIT_3WAY_NW: track == TRACK_UPPER ? track = TRACK_Y : track = TRACK_LEFT; break; + } + if (!IsWaterTile(gp.new_tile) || !IsWaterTile(TileAddByDiagDir(gp.new_tile, _diagdir_to_next_tile[track][diagdir]))) track = old; // Don't bump in coast, don't get stuck. + } + } + b = _ship_subcoord[diagdir][track]; gp.x = (gp.x & ~0xF) | b[0]; diff --git a/src/table/settings.ini b/src/table/settings.ini index 6aade64647..b87123d728 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -1269,6 +1269,15 @@ def = false str = STR_CONFIG_SETTING_IMPROVED_BREAKDOWNS patxname = ""improved_breakdowns.vehicle.improved_breakdowns"" +[SDT_BOOL] +base = GameSettings +var = vehicle.ship_collision_avoidance +def = true +str = STR_CONFIG_SETTING_SHIP_COLLISION_AVOIDANCE +strhelp = STR_CONFIG_SETTING_SHIP_COLLISION_AVOIDANCE_HELPTEXT +patxname = ""ship_collision_avoidance.vehicle.ship_collision_avoidance"" +cat = SC_BASIC + ; station.join_stations [SDT_NULL] length = 1