changeset 15114:b48c203991dc draft

(svn r19743) -Fix: NewGrfs could access map bits of not yet constructed industries and houses during construction callbacks.
author frosch <frosch@openttd.org>
date Sat, 01 May 2010 13:01:21 +0000
parents 4aaf8647d5b4
children a93503fec8db
files src/newgrf_house.cpp src/newgrf_house.h src/newgrf_industries.cpp src/newgrf_industrytiles.cpp src/newgrf_spritegroup.h src/town_cmd.cpp
diffstat 6 files changed, 48 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/src/newgrf_house.cpp
+++ b/src/newgrf_house.cpp
@@ -99,20 +99,25 @@
 
 static uint32 HouseGetRandomBits(const ResolverObject *object)
 {
-	const TileIndex tile = object->u.house.tile;
-	return (tile == INVALID_TILE || !IsTileType(tile, MP_HOUSE)) ? 0 : GetHouseRandomBits(tile);
+	/* Note: Towns build houses over houses. So during construction checks 'tile' may be a valid but unrelated house. */
+	TileIndex tile = object->u.house.tile;
+	assert(IsValidTile(tile) && (object->u.house.not_yet_constructed || IsTileType(tile, MP_HOUSE)));
+	return object->u.house.not_yet_constructed ? 0 : GetHouseRandomBits(tile);
 }
 
 static uint32 HouseGetTriggers(const ResolverObject *object)
 {
-	const TileIndex tile = object->u.house.tile;
-	return (tile == INVALID_TILE || !IsTileType(tile, MP_HOUSE)) ? 0 : GetHouseTriggers(tile);
+	/* Note: Towns build houses over houses. So during construction checks 'tile' may be a valid but unrelated house. */
+	TileIndex tile = object->u.house.tile;
+	assert(IsValidTile(tile) && (object->u.house.not_yet_constructed || IsTileType(tile, MP_HOUSE)));
+	return object->u.house.not_yet_constructed ? 0 : GetHouseTriggers(tile);
 }
 
 static void HouseSetTriggers(const ResolverObject *object, int triggers)
 {
-	const TileIndex tile = object->u.house.tile;
-	if (IsTileType(tile, MP_HOUSE)) SetHouseTriggers(tile, triggers);
+	TileIndex tile = object->u.house.tile;
+	assert(!object->u.house.not_yet_constructed && IsValidTile(tile) && IsTileType(tile, MP_HOUSE));
+	SetHouseTriggers(tile, triggers);
 }
 
 static uint32 GetNumHouses(HouseID house_id, const Town *town)
@@ -370,6 +375,7 @@
 	res->u.house.tile     = tile;
 	res->u.house.town     = town;
 	res->u.house.house_id = house_id;
+	res->u.house.not_yet_constructed = false;
 
 	res->callback        = CBID_NO_CALLBACK;
 	res->callback_param1 = 0;
@@ -383,15 +389,18 @@
 	res->grffile         = (hs != NULL ? hs->grffile : NULL);
 }
 
-uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, HouseID house_id, Town *town, TileIndex tile)
+uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, HouseID house_id, Town *town, TileIndex tile, bool not_yet_constructed)
 {
 	ResolverObject object;
 	const SpriteGroup *group;
 
+	assert(IsValidTile(tile) && (not_yet_constructed || IsTileType(tile, MP_HOUSE)));
+
 	NewHouseResolver(&object, house_id, tile, town);
 	object.callback = callback;
 	object.callback_param1 = param1;
 	object.callback_param2 = param2;
+	object.u.house.not_yet_constructed = not_yet_constructed;
 
 	group = SpriteGroup::Resolve(HouseSpec::Get(house_id)->spritegroup, &object);
 	if (group == NULL) return CALLBACK_FAILED;
--- a/src/newgrf_house.h
+++ b/src/newgrf_house.h
@@ -44,7 +44,7 @@
 void AnimateNewHouseTile(TileIndex tile);
 void ChangeHouseAnimationFrame(const struct GRFFile *file, TileIndex tile, uint16 callback_result);
 
-uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, HouseID house_id, Town *town, TileIndex tile);
+uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, HouseID house_id, Town *town, TileIndex tile, bool not_yet_constructed = false);
 
 bool CanDeleteHouse(TileIndex tile);
 
--- a/src/newgrf_industries.cpp
+++ b/src/newgrf_industries.cpp
@@ -345,18 +345,23 @@
 
 static uint32 IndustryGetRandomBits(const ResolverObject *object)
 {
-	return object->u.industry.ind == NULL ? 0 : object->u.industry.ind->random;
+	const Industry *ind = object->u.industry.ind;
+	assert(ind != NULL);
+	return ind->random;
 }
 
 static uint32 IndustryGetTriggers(const ResolverObject *object)
 {
-	return object->u.industry.ind == NULL ? 0 : object->u.industry.ind->random_triggers;
+	const Industry *ind = object->u.industry.ind;
+	assert(ind != NULL);
+	return ind->random_triggers;
 }
 
 static void IndustrySetTriggers(const ResolverObject *object, int triggers)
 {
-	if (object->u.industry.ind == NULL) return;
-	object->u.industry.ind->random_triggers = triggers;
+	Industry *ind = object->u.industry.ind;
+	assert(ind != NULL && ind->index != INVALID_INDUSTRY);
+	ind->random_triggers = triggers;
 }
 
 static void NewIndustryResolver(ResolverObject *res, TileIndex tile, Industry *indus, IndustryType type)
--- a/src/newgrf_industrytiles.cpp
+++ b/src/newgrf_industrytiles.cpp
@@ -118,26 +118,35 @@
 static uint32 IndustryTileGetRandomBits(const ResolverObject *object)
 {
 	const TileIndex tile = object->u.industry.tile;
-	if (tile == INVALID_TILE || !IsTileType(tile, MP_INDUSTRY)) return 0;
-	return (object->scope == VSG_SCOPE_SELF) ? GetIndustryRandomBits(tile) : Industry::GetByTile(tile)->random;
+	const Industry *ind = object->u.industry.ind;
+	assert(ind != NULL && IsValidTile(tile));
+	assert(ind->index == INVALID_INDUSTRY || IsTileType(tile, MP_INDUSTRY));
+
+	return (object->scope == VSG_SCOPE_SELF) ?
+			(ind->index != INVALID_INDUSTRY ? GetIndustryRandomBits(tile) : 0) :
+			ind->random;
 }
 
 static uint32 IndustryTileGetTriggers(const ResolverObject *object)
 {
 	const TileIndex tile = object->u.industry.tile;
-	if (tile == INVALID_TILE || !IsTileType(tile, MP_INDUSTRY)) return 0;
-	return (object->scope == VSG_SCOPE_SELF) ? GetIndustryTriggers(tile) : Industry::GetByTile(tile)->random_triggers;
+	const Industry *ind = object->u.industry.ind;
+	assert(ind != NULL && IsValidTile(tile));
+	assert(ind->index == INVALID_INDUSTRY || IsTileType(tile, MP_INDUSTRY));
+	if (ind->index == INVALID_INDUSTRY) return 0;
+	return (object->scope == VSG_SCOPE_SELF) ? GetIndustryTriggers(tile) : ind->random_triggers;
 }
 
 static void IndustryTileSetTriggers(const ResolverObject *object, int triggers)
 {
 	const TileIndex tile = object->u.industry.tile;
-	if (tile == INVALID_TILE || !IsTileType(tile, MP_INDUSTRY)) return;
+	Industry *ind = object->u.industry.ind;
+	assert(ind != NULL && ind->index != INVALID_INDUSTRY && IsValidTile(tile) && IsTileType(tile, MP_INDUSTRY));
 
 	if (object->scope == VSG_SCOPE_SELF) {
 		SetIndustryTriggers(tile, triggers);
 	} else {
-		Industry::GetByTile(tile)->random_triggers = triggers;
+		ind->random_triggers = triggers;
 	}
 }
 
@@ -194,6 +203,9 @@
 	ResolverObject object;
 	const SpriteGroup *group;
 
+	assert(industry != NULL && IsValidTile(tile));
+	assert(industry->index == INVALID_INDUSTRY || IsTileType(tile, MP_INDUSTRY));
+
 	NewIndustryTileResolver(&object, gfx_id, tile, industry);
 	object.callback = callback;
 	object.callback_param1 = param1;
@@ -396,6 +408,8 @@
 {
 	ResolverObject object;
 
+	assert(IsValidTile(tile) && IsTileType(tile, MP_INDUSTRY));
+
 	IndustryGfx gfx = GetIndustryGfx(tile);
 	const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
 
--- a/src/newgrf_spritegroup.h
+++ b/src/newgrf_spritegroup.h
@@ -319,6 +319,7 @@
 			TileIndex tile;
 			Town *town;
 			HouseID house_id;
+			bool not_yet_constructed;      ///< True for construction check
 		} house;
 		struct {
 			TileIndex tile;
--- a/src/town_cmd.cpp
+++ b/src/town_cmd.cpp
@@ -2165,7 +2165,7 @@
 		}
 
 		if (HasBit(hs->callback_mask, CBM_HOUSE_ALLOW_CONSTRUCTION)) {
-			uint16 callback_res = GetHouseCallback(CBID_HOUSE_ALLOW_CONSTRUCTION, 0, 0, house, t, tile);
+			uint16 callback_res = GetHouseCallback(CBID_HOUSE_ALLOW_CONSTRUCTION, 0, 0, house, t, tile, true);
 			if (callback_res != CALLBACK_FAILED && GB(callback_res, 0, 8) == 0) continue;
 		}