From 03bfa6e5254fcca2cf4545226fe7b383f651dc84 Mon Sep 17 00:00:00 2001 From: rubidium Date: Thu, 8 Feb 2007 10:00:22 +0000 Subject: [PATCH] (svn r8623) [0.5] -Backport from trunk (8593, 8608, 8619, 8620) -Fix (FS#564): bridges do not get destroyed when the bridge head gets flooded and there is a vehicle on the bridge. -Fix: you were unable to build roads in the scenario editor when there is no town 0, even though there are other towns. -Fix: store the ownership of a water tile in the buoy tile and set the ownership of the water tile when the buoy is removed. This solves the issue of removing ownership from canal tiles thus making is possible for other players to remove the canal tile. -Fix: buoys on canal tiles do not flood anymore. --- road_cmd.c | 2 +- station_cmd.c | 11 ++++++++++- station_map.h | 5 ++++- tunnelbridge_cmd.c | 6 +++--- vehicle.c | 3 ++- vehicle.h | 2 +- water_cmd.c | 39 +++++++++++++++++++++++++++++++++++---- 7 files changed, 56 insertions(+), 12 deletions(-) diff --git a/road_cmd.c b/road_cmd.c index 116efd5476..6c06809a23 100644 --- a/road_cmd.c +++ b/road_cmd.c @@ -293,7 +293,7 @@ int32 CmdBuildRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) /* 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); diff --git a/station_cmd.c b/station_cmd.c index 625d916af3..7929c23424 100644 --- a/station_cmd.c +++ b/station_cmd.c @@ -1895,13 +1895,22 @@ static int32 RemoveBuoy(Station *st, uint32 flags) 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); diff --git a/station_map.h b/station_map.h index c52769b141..0adbd92b30 100644 --- a/station_map.h +++ b/station_map.h @@ -287,7 +287,10 @@ static inline void MakeAirport(TileIndex t, Owner o, StationID sid, byte section 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) diff --git a/tunnelbridge_cmd.c b/tunnelbridge_cmd.c index 7cc2a8ce77..1f24daf264 100644 --- a/tunnelbridge_cmd.c +++ b/tunnelbridge_cmd.c @@ -541,7 +541,7 @@ TileIndex CheckTunnelBusy(TileIndex tile, uint *length) 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 @@ static int32 DoClearBridge(TileIndex tile, uint32 flags) v = FindVehicleBetween( tile + delta, endtile - delta, - GetBridgeHeightRamp(tile) + GetBridgeHeightRamp(tile), false ); if (v != NULL) return_cmd_error(VehicleInTheWayErrMsg(v)); @@ -820,7 +820,7 @@ int32 DoConvertTunnelBridgeRail(TileIndex tile, RailType totype, bool exec) 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); } diff --git a/vehicle.c b/vehicle.c index e5ee778ecb..7b1dde8e7c 100644 --- a/vehicle.c +++ b/vehicle.c @@ -174,7 +174,7 @@ Vehicle *FindVehicleOnTileZ(TileIndex tile, byte z) 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 @@ Vehicle *FindVehicleBetween(TileIndex from, TileIndex to, byte z) 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) { diff --git a/vehicle.h b/vehicle.h index 20c1b70184..a4377572de 100644 --- a/vehicle.h +++ b/vehicle.h @@ -299,7 +299,7 @@ Vehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVeh 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); diff --git a/water_cmd.c b/water_cmd.c index 8af293b95c..81ca489295 100644 --- a/water_cmd.c +++ b/water_cmd.c @@ -40,6 +40,7 @@ const SpriteID _water_shore_sprites[15] = { }; +static Vehicle *FindFloodableVehicleOnTile(TileIndex tile); static void FloodVehicle(Vehicle *v); /** Build a ship depot. @@ -593,7 +594,7 @@ static void TileLoopWaterHelper(TileIndex tile, const TileIndexDiffC *offs) _current_player = OWNER_WATER; { - Vehicle *v = FindVehicleOnTileZ(target, 0); + Vehicle *v = FindFloodableVehicleOnTile(target); if (v != NULL) FloodVehicle(v); } @@ -604,6 +605,36 @@ static void TileLoopWaterHelper(TileIndex tile, const TileIndexDiffC *offs) } } +/** + * 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 @@ static void FloodVehicle(Vehicle *v) 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 @@ void TileLoop_Water(TileIndex tile) {{ 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)) {