changeset 15924:f7897e388f39 draft

(svn r20609) -Fix [FS#3702]: crash when a NewGRF defined an invalid substitute type for a house and the NewGRF was removed during the game
author yexo <yexo@openttd.org>
date Tue, 24 Aug 2010 16:00:35 +0000
parents fb2cc4b4fa4a
children 197b55354472
files src/saveload/town_sl.cpp
diffstat 1 files changed, 40 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/saveload/town_sl.cpp
+++ b/src/saveload/town_sl.cpp
@@ -36,18 +36,55 @@
 	}
 
 	for (TileIndex t = 0; t < MapSize(); t++) {
-		HouseID house_id;
-
 		if (!IsTileType(t, MP_HOUSE)) continue;
 
-		house_id = GetCleanHouseType(t);
+		HouseID house_id = GetCleanHouseType(t);
 		if (!HouseSpec::Get(house_id)->enabled && house_id >= NEW_HOUSE_OFFSET) {
 			/* The specs for this type of house are not available any more, so
 			 * replace it with the substitute original house type. */
 			house_id = _house_mngr.GetSubstituteID(house_id);
 			SetHouseType(t, house_id);
 		}
+	}
 
+	/* Check for cases when a NewGRF has set a wrong house substitute type. */
+	for (TileIndex t = 0; t < MapSize(); t++) {
+		if (!IsTileType(t, MP_HOUSE)) continue;
+
+		HouseID house_type = GetCleanHouseType(t);
+		TileIndex north_tile = t + GetHouseNorthPart(house_type); // modifies 'house_type'!
+		if (t == north_tile) {
+			const HouseSpec *hs = HouseSpec::Get(house_type);
+			bool valid_house = true;
+			if (hs->building_flags & TILE_SIZE_2x1) {
+				TileIndex tile = t + TileDiffXY(1, 0);
+				if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 1) valid_house = false;
+			} else if (hs->building_flags & TILE_SIZE_1x2) {
+				TileIndex tile = t + TileDiffXY(0, 1);
+				if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 1) valid_house = false;
+			} else if (hs->building_flags & TILE_SIZE_2x2) {
+				TileIndex tile = t + TileDiffXY(1, 0);
+				if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 1) valid_house = false;
+				tile = t + TileDiffXY(0, 1);
+				if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 2) valid_house = false;
+				tile = t + TileDiffXY(1, 1);
+				if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 3) valid_house = false;
+			}
+			/* If not all tiles of this house are present remove the house.
+			 * The other tiles will get removed later in this loop because
+			 * their north tile is not the correct type anymore. */
+			if (!valid_house) DoClearSquare(t);
+		} else if (!IsTileType(north_tile, MP_HOUSE) || GetCleanHouseType(north_tile) != house_type) {
+			/* This tile should be part of a multi-tile building but the
+			 * north tile of this house isn't on the map. */
+			DoClearSquare(t);
+		}
+	}
+
+	for (TileIndex t = 0; t < MapSize(); t++) {
+		if (!IsTileType(t, MP_HOUSE)) continue;
+
+		HouseID house_id = GetCleanHouseType(t);
 		town = Town::GetByTile(t);
 		IncreaseBuildingCount(town, house_id);
 		if (IsHouseCompleted(t)) town->population += HouseSpec::Get(house_id)->population;