Merge branch 'ship_collision_avoidance' into jgrpp
This commit is contained in:
@@ -1265,7 +1265,7 @@ STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES :{WHITE}Changing
|
|||||||
STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE :Infrastructure maintenance: {STRING2}
|
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_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 :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_SHIP_COLLISION_AVOIDANCE_HELPTEXT :When enabled, ships try to avoid passing through each other. The best results are obtained when 90° turns are forbidden.
|
||||||
|
|
||||||
STR_CONFIG_SETTING_CHUNNEL :Allow construction of tunnels under water: {STRING2}
|
STR_CONFIG_SETTING_CHUNNEL :Allow construction of tunnels under water: {STRING2}
|
||||||
STR_CONFIG_SETTING_CHUNNEL_HELPTEXT :When enabled, tunnels can be constructed under bodies of water at sea level. This requires the tunnel ends to be least 3 tiles away from the shore.
|
STR_CONFIG_SETTING_CHUNNEL_HELPTEXT :When enabled, tunnels can be constructed under bodies of water at sea level. This requires the tunnel ends to be least 3 tiles away from the shore.
|
||||||
|
@@ -551,9 +551,9 @@ static const byte _ship_subcoord[4][6][3] = {
|
|||||||
/** Temporary data storage for testing collisions. */
|
/** Temporary data storage for testing collisions. */
|
||||||
struct ShipCollideChecker {
|
struct ShipCollideChecker {
|
||||||
|
|
||||||
TrackBits track_bits; ///< Pathfinder chosen track converted to trackbits, or is v->state of requesting ship. (one bit set)
|
TrackBits track_bits; ///< Pathfinder chosen track converted to trackbits, or is v->state of requesting ship. (one bit set)
|
||||||
TileIndex tile; ///< Tile where ship was found, used to determine distance between ships.
|
TileIndex search_tile; ///< The tile that we really want to check.
|
||||||
int32 z_pos; ///< z_pos of requesting ship.
|
Ship *v; ///< Ship we are testing for collision.
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Helper function for collision avoidance. */
|
/** Helper function for collision avoidance. */
|
||||||
@@ -568,13 +568,40 @@ static Vehicle *FindShipOnTile(Vehicle *v, void *data)
|
|||||||
if (bits == TRACK_BIT_HORZ || bits == TRACK_BIT_VERT) return NULL;
|
if (bits == TRACK_BIT_HORZ || bits == TRACK_BIT_VERT) return NULL;
|
||||||
|
|
||||||
/* Don't detect ships passing on aquaduct. */
|
/* Don't detect ships passing on aquaduct. */
|
||||||
if (abs(v->z_pos - scc->z_pos) >= 8) return NULL;
|
if (abs(v->z_pos - scc->v->z_pos) >= 8) return NULL;
|
||||||
|
|
||||||
scc->tile = v->tile;
|
/* Only requested tiles are checked. avoid desync. */
|
||||||
|
if (TileVirtXY(v->x_pos, v->y_pos) != scc->search_tile) return NULL;
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjust speed while on aqueducts.
|
||||||
|
* @param search_tile Tile that the requesting ship will check, one will be added to look in front of the bow.
|
||||||
|
* @param ramp Ramp tile from aqueduct.
|
||||||
|
* @param v Ship that does the request.
|
||||||
|
* @return Allways false.
|
||||||
|
*/
|
||||||
|
static bool HandleSpeedOnAqueduct(Ship *v, TileIndex tile, TileIndex ramp)
|
||||||
|
{
|
||||||
|
TileIndexDiffC ti = TileIndexDiffCByDir(v->direction);
|
||||||
|
|
||||||
|
ShipCollideChecker scc;
|
||||||
|
scc.v = v;
|
||||||
|
scc.track_bits = TRACK_BIT_NONE;
|
||||||
|
scc.search_tile = TileAddWrap(tile, ti.x, ti.y);
|
||||||
|
|
||||||
|
if (scc.search_tile == INVALID_TILE) return false;
|
||||||
|
|
||||||
|
if (IsValidTile(scc.search_tile) &&
|
||||||
|
(HasVehicleOnPos(ramp, &scc, FindShipOnTile) ||
|
||||||
|
HasVehicleOnPos(GetOtherTunnelBridgeEnd(ramp), &scc, FindShipOnTile))) {
|
||||||
|
v->cur_speed /= 4;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If there is imminent collision or worse, direction and speed will be adjusted.
|
* If there is imminent collision or worse, direction and speed will be adjusted.
|
||||||
* @param tile Tile that the ship is about to enter.
|
* @param tile Tile that the ship is about to enter.
|
||||||
@@ -594,27 +621,39 @@ static void CheckDistanceBetweenShips(TileIndex tile, Ship *v, TrackBits tracks,
|
|||||||
/* Only check for collision when pathfinder did not change direction.
|
/* Only check for collision when pathfinder did not change direction.
|
||||||
* This is done in order to keep ships moving towards the intended target. */
|
* This is done in order to keep ships moving towards the intended target. */
|
||||||
TrackBits combine = (v->state | track_bits);
|
TrackBits combine = (v->state | track_bits);
|
||||||
if (combine != TRACK_BIT_HORZ && combine != TRACK_BIT_VERT && combine != track_bits && v->state != TRACK_BIT_WORMHOLE) return;
|
if (combine != TRACK_BIT_HORZ && combine != TRACK_BIT_VERT && combine != track_bits) return;
|
||||||
|
|
||||||
TileIndex tile_plus_one = TileAddByDiagDir(tile, _ship_search_directions[track][diagdir]);
|
|
||||||
if (!IsValidTile(tile_plus_one)) tile_plus_one = tile;
|
|
||||||
TileIndex tile_plus_two = TileAddByDiagDir(tile_plus_one, diagdir);
|
|
||||||
if (!IsValidTile(tile_plus_two)) tile_plus_two = tile_plus_one;
|
|
||||||
|
|
||||||
|
TileIndexDiffC ti;
|
||||||
ShipCollideChecker scc;
|
ShipCollideChecker scc;
|
||||||
scc.z_pos = v->z_pos;
|
scc.v = v;
|
||||||
|
|
||||||
scc.track_bits = track_bits;
|
scc.track_bits = track_bits;
|
||||||
|
scc.search_tile = tile;
|
||||||
|
|
||||||
bool found = HasVehicleOnPos(tile, &scc, FindShipOnTile);
|
bool found = HasVehicleOnPos(tile, &scc, FindShipOnTile);
|
||||||
scc.track_bits = v->state;
|
|
||||||
if (!found) found = HasVehicleOnPos(tile_plus_one, &scc, FindShipOnTile);
|
|
||||||
scc.track_bits = track_bits;
|
|
||||||
if (!found) found = HasVehicleOnPos(tile_plus_two, &scc, FindShipOnTile);
|
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
/* Bridge entrance */
|
||||||
|
if (IsBridgeTile(tile) && HandleSpeedOnAqueduct(v, tile, tile)) return;
|
||||||
|
|
||||||
|
scc.track_bits = v->state;
|
||||||
|
ti = TileIndexDiffCByDiagDir(_ship_search_directions[track][diagdir]);
|
||||||
|
scc.search_tile = TileAddWrap(tile, ti.x, ti.y);
|
||||||
|
if (scc.search_tile == INVALID_TILE) return;
|
||||||
|
|
||||||
|
found = HasVehicleOnPos(scc.search_tile, &scc, FindShipOnTile);
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
scc.track_bits = track_bits;
|
||||||
|
ti = TileIndexDiffCByDiagDir(diagdir);
|
||||||
|
scc.search_tile = TileAddWrap(scc.search_tile, ti.x, ti.y);
|
||||||
|
if (scc.search_tile == INVALID_TILE) return;
|
||||||
|
|
||||||
|
found = HasVehicleOnPos(scc.search_tile, &scc, FindShipOnTile);
|
||||||
|
}
|
||||||
if (found) {
|
if (found) {
|
||||||
|
|
||||||
/* Speed adjustment related to distance. */
|
/* Speed adjustment related to distance. */
|
||||||
v->cur_speed /= scc.tile == tile ? 8 : 2;
|
v->cur_speed /= scc.search_tile == tile ? 8 : 2;
|
||||||
|
|
||||||
/* Clean none wanted trackbits, including pathfinder track, TRACK_BIT_WORMHOLE and no 90 degree turns. */
|
/* Clean none wanted trackbits, including pathfinder track, TRACK_BIT_WORMHOLE and no 90 degree turns. */
|
||||||
tracks = IsDiagonalTrack(track) ? KillFirstBit(tracks) : (tracks & TRACK_BIT_CROSS);
|
tracks = IsDiagonalTrack(track) ? KillFirstBit(tracks) : (tracks & TRACK_BIT_CROSS);
|
||||||
@@ -623,10 +662,11 @@ static void CheckDistanceBetweenShips(TileIndex tile, Ship *v, TrackBits tracks,
|
|||||||
while (tracks != TRACK_BIT_NONE) {
|
while (tracks != TRACK_BIT_NONE) {
|
||||||
track = RemoveFirstTrack(&tracks);
|
track = RemoveFirstTrack(&tracks);
|
||||||
|
|
||||||
TileIndex tile_check = TileAddByDiagDir(tile, _ship_search_directions[track][diagdir]);
|
ti = TileIndexDiffCByDiagDir(_ship_search_directions[track][diagdir]);
|
||||||
if (!IsValidTile(tile_check)) continue;
|
TileIndex tile_check = TileAddWrap(tile, ti.x, ti.y);
|
||||||
|
if (tile_check == INVALID_TILE) continue;
|
||||||
|
|
||||||
if (HasVehicleOnPos(tile_check, &scc, &FindShipOnTile)) continue;
|
if (HasVehicleOnPos(tile_check, &scc, FindShipOnTile)) continue;
|
||||||
|
|
||||||
TrackBits bits = GetAvailShipTracks(tile_check, _ship_search_directions[track][diagdir]);
|
TrackBits bits = GetAvailShipTracks(tile_check, _ship_search_directions[track][diagdir]);
|
||||||
if (!IsDiagonalTrack(track)) bits &= TRACK_BIT_CROSS; // No 90 degree turns.
|
if (!IsDiagonalTrack(track)) bits &= TRACK_BIT_CROSS; // No 90 degree turns.
|
||||||
@@ -757,12 +797,15 @@ static void ShipController(Ship *v)
|
|||||||
} else {
|
} else {
|
||||||
/* On a bridge */
|
/* On a bridge */
|
||||||
if (!IsTileType(gp.new_tile, MP_TUNNELBRIDGE) || !HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
|
if (!IsTileType(gp.new_tile, MP_TUNNELBRIDGE) || !HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
|
||||||
|
if (_settings_game.vehicle.ship_collision_avoidance && gp.new_tile != TileVirtXY(v->x_pos, v->y_pos)) HandleSpeedOnAqueduct(v, gp.new_tile, v->tile);
|
||||||
v->x_pos = gp.x;
|
v->x_pos = gp.x;
|
||||||
v->y_pos = gp.y;
|
v->y_pos = gp.y;
|
||||||
v->UpdatePosition();
|
v->UpdatePosition();
|
||||||
if ((v->vehstatus & VS_HIDDEN) == 0) v->Vehicle::UpdateViewport(true);
|
if ((v->vehstatus & VS_HIDDEN) == 0) v->Vehicle::UpdateViewport(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/* Bridge exit */
|
||||||
|
if (_settings_game.vehicle.ship_collision_avoidance && gp.new_tile != TileVirtXY(v->x_pos, v->y_pos)) HandleSpeedOnAqueduct(v, gp.new_tile, v->tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update image of ship, as well as delta XY */
|
/* update image of ship, as well as delta XY */
|
||||||
|
Reference in New Issue
Block a user