--- a/road_cmd.c Wed Jan 31 22:08:23 2007 +0000
+++ b/road_cmd.c Thu Feb 08 10:00:22 2007 +0000
@@ -293,7 +293,7 @@
/* Road pieces are max 4 bitset values (NE, NW, SE, SW) and town can only be non-zero
* if a non-player is building the road */
- if ((p1 >> 4) || (IsValidPlayer(_current_player) && p2 != 0) || !IsValidTownID(p2)) return CMD_ERROR;
+ if ((p1 >> 4) || (IsValidPlayer(_current_player) && p2 != 0) || (_current_player == OWNER_TOWN && !IsValidTownID(p2))) return CMD_ERROR;
pieces = p1;
tileh = GetTileSlope(tile, NULL);
--- a/station_cmd.c Wed Jan 31 22:08:23 2007 +0000
+++ b/station_cmd.c Thu Feb 08 10:00:22 2007 +0000
@@ -1895,13 +1895,22 @@
if (!EnsureNoVehicle(tile)) return CMD_ERROR;
if (flags & DC_EXEC) {
+ Owner o;
st->dock_tile = 0;
/* Buoys are marked in the Station struct by this flag. Yes, it is this
* braindead.. */
st->facilities &= ~FACIL_DOCK;
st->had_vehicle_of_type &= ~HVOT_BUOY;
- MakeWater(tile);
+ /* We have to set the water tile's state to the same state as before the
+ * buoy was placed. Otherwise one could plant a buoy on a canal edge,
+ * remove it and flood the land (if the canal edge is at level 0) */
+ o = GetTileOwner(tile);
+ if (o == OWNER_WATER) {
+ MakeWater(tile);
+ } else {
+ MakeCanal(tile, o);
+ }
MarkTileDirtyByTile(tile);
UpdateStationVirtCoordDirty(st);
--- a/station_map.h Wed Jan 31 22:08:23 2007 +0000
+++ b/station_map.h Thu Feb 08 10:00:22 2007 +0000
@@ -287,7 +287,10 @@
static inline void MakeBuoy(TileIndex t, StationID sid)
{
- MakeStation(t, OWNER_NONE, sid, GFX_BUOY_BASE);
+ /* Make the owner of the buoy tile the same as the current owner of the
+ * water tile. In this way, we can reset the owner of the water to its
+ * original state when the buoy gets removed. */
+ MakeStation(t, GetTileOwner(t), sid, GFX_BUOY_BASE);
}
static inline void MakeDock(TileIndex t, Owner o, StationID sid, DiagDirection d)
--- a/tunnelbridge_cmd.c Wed Jan 31 22:08:23 2007 +0000
+++ b/tunnelbridge_cmd.c Thu Feb 08 10:00:22 2007 +0000
@@ -541,7 +541,7 @@
GetTileZ(tile) != z
);
- v = FindVehicleBetween(starttile, tile, z);
+ v = FindVehicleBetween(starttile, tile, z, false);
if (v != NULL) {
_error_message = v->type == VEH_Train ?
STR_5000_TRAIN_IN_TUNNEL : STR_5001_ROAD_VEHICLE_IN_TUNNEL;
@@ -688,7 +688,7 @@
v = FindVehicleBetween(
tile + delta,
endtile - delta,
- GetBridgeHeightRamp(tile)
+ GetBridgeHeightRamp(tile), false
);
if (v != NULL) return_cmd_error(VehicleInTheWayErrMsg(v));
@@ -820,7 +820,7 @@
if (!EnsureNoVehicle(tile) ||
!EnsureNoVehicle(endtile) ||
- FindVehicleBetween(tile, endtile, GetBridgeHeightRamp(tile)) != NULL) {
+ FindVehicleBetween(tile, endtile, GetBridgeHeightRamp(tile), false) != NULL) {
return_cmd_error(STR_8803_TRAIN_IN_THE_WAY);
}
--- a/vehicle.c Wed Jan 31 22:08:23 2007 +0000
+++ b/vehicle.c Thu Feb 08 10:00:22 2007 +0000
@@ -174,7 +174,7 @@
return VehicleFromPos(tile, &ti, EnsureNoVehicleProcZ);
}
-Vehicle *FindVehicleBetween(TileIndex from, TileIndex to, byte z)
+Vehicle *FindVehicleBetween(TileIndex from, TileIndex to, byte z, bool without_crashed)
{
int x1 = TileX(from);
int y1 = TileY(from);
@@ -188,6 +188,7 @@
intswap(y1,y2);
}
FOR_ALL_VEHICLES(veh) {
+ if (without_crashed && (veh->vehstatus & VS_CRASHED) != 0) continue;
if ((veh->type == VEH_Train || veh->type == VEH_Road) && (z==0xFF || veh->z_pos == z)) {
if ((veh->x_pos>>4) >= x1 && (veh->x_pos>>4) <= x2 &&
(veh->y_pos>>4) >= y1 && (veh->y_pos>>4) <= y2) {
--- a/vehicle.h Wed Jan 31 22:08:23 2007 +0000
+++ b/vehicle.h Thu Feb 08 10:00:22 2007 +0000
@@ -299,7 +299,7 @@
uint32 VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y);
StringID VehicleInTheWayErrMsg(const Vehicle* v);
-Vehicle *FindVehicleBetween(TileIndex from, TileIndex to, byte z);
+Vehicle *FindVehicleBetween(TileIndex from, TileIndex to, byte z, bool without_crashed);
TileIndex GetVehicleOutOfTunnelTile(const Vehicle *v);
bool UpdateSignalsOnSegment(TileIndex tile, DiagDirection direction);
--- a/water_cmd.c Wed Jan 31 22:08:23 2007 +0000
+++ b/water_cmd.c Thu Feb 08 10:00:22 2007 +0000
@@ -40,6 +40,7 @@
};
+static Vehicle *FindFloodableVehicleOnTile(TileIndex tile);
static void FloodVehicle(Vehicle *v);
/** Build a ship depot.
@@ -593,7 +594,7 @@
_current_player = OWNER_WATER;
{
- Vehicle *v = FindVehicleOnTileZ(target, 0);
+ Vehicle *v = FindFloodableVehicleOnTile(target);
if (v != NULL) FloodVehicle(v);
}
@@ -604,6 +605,36 @@
}
}
+/**
+ * Finds a vehicle to flood.
+ * It does not find vehicles that are already crashed on bridges, i.e. flooded.
+ * @param tile the tile where to find a vehicle to flood
+ * @return a vehicle too flood or NULL when there is no vehicle too flood.
+ */
+static Vehicle *FindFloodableVehicleOnTile(TileIndex tile)
+{
+ TileIndex end;
+ byte z;
+ Vehicle *v;
+
+ if (!IsBridgeTile(tile)) return FindVehicleOnTileZ(tile, 0);
+
+ end = GetOtherBridgeEnd(tile);
+ z = GetBridgeHeight(tile);
+
+ /* check the start tile first since as this is closest to the water */
+ v = FindVehicleOnTileZ(tile, z);
+ if (v != NULL && (v->vehstatus & VS_CRASHED) == 0) return v;
+
+ /* check a vehicle in between both bridge heads */
+ v = FindVehicleBetween(tile, end, z, true);
+ if (v != NULL) return v;
+
+ /* check the end tile last to give fleeing vehicles a chance to escape */
+ v = FindVehicleOnTileZ(end, z);
+ return (v != NULL && (v->vehstatus & VS_CRASHED) == 0) ? v : NULL;
+}
+
static void FloodVehicle(Vehicle *v)
{
if (!(v->vehstatus & VS_CRASHED)) {
@@ -628,6 +659,7 @@
BEGIN_ENUM_WAGONS(v)
if (v->cargo_type == CT_PASSENGERS) pass += v->cargo_count;
v->vehstatus |= VS_CRASHED;
+ MarkAllViewportsDirty(v->left_coord, v->top_coord, v->right_coord + 1, v->bottom_coord + 1);
END_ENUM_WAGONS(v)
v = u;
@@ -661,9 +693,8 @@
{{ 0, -1}, {0, 0}, {1, 0}, { 0, -1}, { 1, -1}}
};
- /* Ensure sea-level canals do not flood */
- if ((IsTileType(tile, MP_WATER) || IsTileType(tile, MP_TUNNELBRIDGE)) &&
- !IsTileOwner(tile, OWNER_WATER)) return;
+ /* Ensure sea-level canals and buoys on canal borders do not flood */
+ if ((IsTileType(tile, MP_WATER) || IsTileType(tile, MP_TUNNELBRIDGE) || IsBuoyTile(tile)) && !IsTileOwner(tile, OWNER_WATER)) return;
if (IS_INT_INSIDE(TileX(tile), 1, MapSizeX() - 3 + 1) &&
IS_INT_INSIDE(TileY(tile), 1, MapSizeY() - 3 + 1)) {