Changeset - r18301:0c1dfbaba57a
[Not reviewed]
master
0 11 0
frosch - 13 years ago 2011-11-08 17:26:49
frosch@openttd.org
(svn r23147) -Change: [NewGRF v8] Unify the return values of boolean callbacks, and check the results for validity.
11 files changed with 90 insertions and 28 deletions:
0 comments (0 inline, 0 general)
src/industry_cmd.cpp
Show inline comments
 
@@ -372,25 +372,25 @@ static int GetSlopePixelZ_Industry(TileI
 
static Foundation GetFoundation_Industry(TileIndex tile, Slope tileh)
 
{
 
	IndustryGfx gfx = GetIndustryGfx(tile);
 

	
 
	/* For NewGRF industry tiles we might not be drawing a foundation. We need to
 
	 * account for this, as other structures should
 
	 * draw the wall of the foundation in this case.
 
	 */
 
	if (gfx >= NEW_INDUSTRYTILEOFFSET) {
 
		const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
 
		if (indts->grf_prop.spritegroup[0] != NULL && HasBit(indts->callback_mask, CBM_INDT_DRAW_FOUNDATIONS)) {
 
			uint32 callback_res = GetIndustryTileCallback(CBID_INDTILE_DRAW_FOUNDATIONS, 0, 0, gfx, Industry::GetByTile(tile), tile);
 
			if (callback_res == 0) return FOUNDATION_NONE;
 
			if (callback_res != CALLBACK_FAILED && !ConvertBooleanCallback(indts->grf_prop.grffile, CBID_INDTILE_DRAW_FOUNDATIONS, callback_res)) return FOUNDATION_NONE;
 
		}
 
	}
 
	return FlatteningFoundation(tileh);
 
}
 

	
 
static void AddAcceptedCargo_Industry(TileIndex tile, CargoArray &acceptance, uint32 *always_accepted)
 
{
 
	IndustryGfx gfx = GetIndustryGfx(tile);
 
	const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
 

	
 
	/* When we have to use a callback, we put our data in the next two variables */
 
	CargoID raw_accepts_cargo[lengthof(itspec->accepts_cargo)];
 
@@ -1094,37 +1094,49 @@ static void ProduceIndustryGoods(Industr
 

	
 
	i->counter--;
 

	
 
	/* produce some cargo */
 
	if ((i->counter % INDUSTRY_PRODUCE_TICKS) == 0) {
 
		if (HasBit(indsp->callback_mask, CBM_IND_PRODUCTION_256_TICKS)) IndustryProductionCallback(i, 1);
 

	
 
		IndustryBehaviour indbehav = indsp->behaviour;
 
		i->produced_cargo_waiting[0] = min(0xffff, i->produced_cargo_waiting[0] + i->production_rate[0]);
 
		i->produced_cargo_waiting[1] = min(0xffff, i->produced_cargo_waiting[1] + i->production_rate[1]);
 

	
 
		if ((indbehav & INDUSTRYBEH_PLANT_FIELDS) != 0) {
 
			bool plant;
 
			uint16 cb_res = CALLBACK_FAILED;
 
			if (HasBit(indsp->callback_mask, CBM_IND_SPECIAL_EFFECT)) {
 
				plant = (GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 0, i, i->type, i->location.tile) != 0);
 
				cb_res = GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 0, i, i->type, i->location.tile);
 
			}
 

	
 
			bool plant;
 
			if (cb_res != CALLBACK_FAILED) {
 
				plant = ConvertBooleanCallback(indsp->grf_prop.grffile, CBID_INDUSTRY_SPECIAL_EFFECT, cb_res);
 
			} else {
 
				plant = Chance16(1, 8);
 
			}
 

	
 
			if (plant) PlantRandomFarmField(i);
 
		}
 
		if ((indbehav & INDUSTRYBEH_CUT_TREES) != 0) {
 
			bool cut = ((i->counter % INDUSTRY_CUT_TREE_TICKS) == 0);
 
			uint16 cb_res = CALLBACK_FAILED;
 
			if (HasBit(indsp->callback_mask, CBM_IND_SPECIAL_EFFECT)) {
 
				cut = (GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 1, i, i->type, i->location.tile) != 0);
 
				cb_res = GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 1, i, i->type, i->location.tile);
 
			}
 

	
 
			bool cut;
 
			if (cb_res != CALLBACK_FAILED) {
 
				cut = ConvertBooleanCallback(indsp->grf_prop.grffile, CBID_INDUSTRY_SPECIAL_EFFECT, cb_res);
 
			} else {
 
				cut = ((i->counter % INDUSTRY_CUT_TREE_TICKS) == 0);
 
			}
 

	
 
			if (cut) ChopLumberMillTrees(i);
 
		}
 

	
 
		TriggerIndustry(i, INDUSTRY_TRIGGER_INDUSTRY_TICK);
 
		StartStopIndustryTileAnimation(i, IAT_INDUSTRY_TICK);
 
	}
 
}
 

	
 
void OnTick_Industry()
 
{
 
@@ -2725,25 +2737,25 @@ static CommandCost TerraformTile_Industr
 
		 *  - Disallow autoslope if callback succeeds and returns non-zero.
 
		 */
 
		Slope tileh_old = GetTileSlope(tile);
 
		/* TileMaxZ must not be changed. Slopes must not be steep. */
 
		if (!IsSteepSlope(tileh_old) && !IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) {
 
			const IndustryGfx gfx = GetIndustryGfx(tile);
 
			const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
 

	
 
			/* Call callback 3C 'disable autosloping for industry tiles'. */
 
			if (HasBit(itspec->callback_mask, CBM_INDT_AUTOSLOPE)) {
 
				/* If the callback fails, allow autoslope. */
 
				uint16 res = GetIndustryTileCallback(CBID_INDTILE_AUTOSLOPE, 0, 0, gfx, Industry::GetByTile(tile), tile);
 
				if ((res == 0) || (res == CALLBACK_FAILED)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
 
				if (res == CALLBACK_FAILED || !ConvertBooleanCallback(itspec->grf_prop.grffile, CBID_INDTILE_AUTOSLOPE, res)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
 
			} else {
 
				/* allow autoslope */
 
				return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
 
			}
 
		}
 
	}
 
	return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 
}
 

	
 
extern const TileTypeProcs _tile_type_industry_procs = {
 
	DrawTile_Industry,           // draw_tile_proc
 
	GetSlopePixelZ_Industry,     // get_slope_z_proc
src/newgrf_airporttiles.cpp
Show inline comments
 
@@ -278,25 +278,25 @@ static void AirportDrawTileLayout(const 
 
}
 

	
 
bool DrawNewAirportTile(TileInfo *ti, Station *st, StationGfx gfx, const AirportTileSpec *airts)
 
{
 
	const SpriteGroup *group;
 
	ResolverObject object;
 

	
 
	if (ti->tileh != SLOPE_FLAT) {
 
		bool draw_old_one = true;
 
		if (HasBit(airts->callback_mask, CBM_AIRT_DRAW_FOUNDATIONS)) {
 
			/* Called to determine the type (if any) of foundation to draw */
 
			uint32 callback_res = GetAirportTileCallback(CBID_AIRPTILE_DRAW_FOUNDATIONS, 0, 0, airts, st, ti->tile);
 
			draw_old_one = (callback_res != 0);
 
			if (callback_res != CALLBACK_FAILED) draw_old_one = ConvertBooleanCallback(airts->grf_prop.grffile, CBID_AIRPTILE_DRAW_FOUNDATIONS, callback_res);
 
		}
 

	
 
		if (draw_old_one) DrawFoundation(ti, FOUNDATION_LEVELED);
 
	}
 

	
 
	AirportTileResolver(&object, airts, ti->tile, st);
 

	
 
	group = SpriteGroup::Resolve(airts->grf_prop.spritegroup[0], &object);
 
	if (group == NULL || group->type != SGT_TILELAYOUT) {
 
		return false;
 
	}
 

	
src/newgrf_commons.cpp
Show inline comments
 
@@ -529,24 +529,63 @@ void ErrorUnknownCallbackResult(uint32 g
 
	char buffer[512];
 

	
 
	SetDParamStr(0, grfconfig->GetName());
 
	GetString(buffer, STR_NEWGRF_BUGGY, lastof(buffer));
 
	DEBUG(grf, 0, "%s", buffer + 3);
 

	
 
	SetDParam(1, cbid);
 
	SetDParam(2, cb_res);
 
	GetString(buffer, STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT, lastof(buffer));
 
	DEBUG(grf, 0, "%s", buffer + 3);
 
}
 

	
 
/**
 
 * Converts a callback result into a boolean.
 
 * For grf version < 8 the result is checked for zero or non-zero.
 
 * For grf version >= 8 the callback result must be 0 or 1.
 
 * @param grffile NewGRF returning the value.
 
 * @param cbid Callback returning the value.
 
 * @param cb_res Callback result.
 
 * @return Boolean value. True if cb_res != 0.
 
 */
 
bool ConvertBooleanCallback(const GRFFile *grffile, uint16 cbid, uint16 cb_res)
 
{
 
	assert(cb_res != CALLBACK_FAILED); // We do not know what to return
 

	
 
	if (grffile->grf_version < 8) return cb_res != 0;
 

	
 
	if (cb_res > 1) ErrorUnknownCallbackResult(grffile->grfid, cbid, cb_res);
 
	return cb_res != 0;
 
}
 

	
 
/**
 
 * Converts a callback result into a boolean.
 
 * For grf version < 8 the first 8 bit of the result are checked for zero or non-zero.
 
 * For grf version >= 8 the callback result must be 0 or 1.
 
 * @param grffile NewGRF returning the value.
 
 * @param cbid Callback returning the value.
 
 * @param cb_res Callback result.
 
 * @return Boolean value. True if cb_res != 0.
 
 */
 
bool Convert8bitBooleanCallback(const GRFFile *grffile, uint16 cbid, uint16 cb_res)
 
{
 
	assert(cb_res != CALLBACK_FAILED); // We do not know what to return
 

	
 
	if (grffile->grf_version < 8) return GB(cb_res, 0, 8) != 0;
 

	
 
	if (cb_res > 1) ErrorUnknownCallbackResult(grffile->grfid, cbid, cb_res);
 
	return cb_res != 0;
 
}
 

	
 

	
 
/* static */ SmallVector<DrawTileSeqStruct, 8> NewGRFSpriteLayout::result_seq;
 

	
 
/**
 
 * Clone the building sprites of a spritelayout.
 
 * @param source The building sprites to copy.
 
 */
 
void NewGRFSpriteLayout::Clone(const DrawTileSeqStruct *source)
 
{
 
	assert(this->seq == NULL);
 
	assert(source != NULL);
 

	
 
	size_t count = 1; // 1 for the terminator
src/newgrf_commons.h
Show inline comments
 
@@ -292,24 +292,26 @@ extern IndustryOverrideManager _industry
 
extern IndustryTileOverrideManager _industile_mngr;
 
extern AirportOverrideManager _airport_mngr;
 
extern AirportTileOverrideManager _airporttile_mngr;
 
extern ObjectOverrideManager _object_mngr;
 

	
 
uint32 GetTerrainType(TileIndex tile, TileContext context = TCX_NORMAL);
 
TileIndex GetNearbyTile(byte parameter, TileIndex tile, bool signed_offsets = true, Axis axis = INVALID_AXIS);
 
uint32 GetNearbyTileInformation(TileIndex tile);
 
uint32 GetCompanyInfo(CompanyID owner, const struct Livery *l = NULL);
 
CommandCost GetErrorMessageFromLocationCallbackResult(uint16 cb_res, uint32 grfid, StringID default_error);
 

	
 
void ErrorUnknownCallbackResult(uint32 grfid, uint16 cbid, uint16 cb_res);
 
bool ConvertBooleanCallback(const struct GRFFile *grffile, uint16 cbid, uint16 cb_res);
 
bool Convert8bitBooleanCallback(const struct GRFFile *grffile, uint16 cbid, uint16 cb_res);
 

	
 
/**
 
 * Data related to the handling of grf files.
 
 * @tparam Tcnt Number of spritegroups
 
 */
 
template <size_t Tcnt>
 
struct GRFFilePropsBase {
 
	GRFFilePropsBase() : local_id(0), grffile(0)
 
	{
 
		/* The lack of some compilers to provide default constructors complying to the specs
 
		 * requires us to zero the stuff ourself. */
 
		memset(spritegroup, 0, sizeof(spritegroup));
src/newgrf_house.cpp
Show inline comments
 
@@ -480,25 +480,25 @@ static void DrawTileLayout(const TileInf
 

	
 
void DrawNewHouseTile(TileInfo *ti, HouseID house_id)
 
{
 
	const HouseSpec *hs = HouseSpec::Get(house_id);
 
	const SpriteGroup *group;
 
	ResolverObject object;
 

	
 
	if (ti->tileh != SLOPE_FLAT) {
 
		bool draw_old_one = true;
 
		if (HasBit(hs->callback_mask, CBM_HOUSE_DRAW_FOUNDATIONS)) {
 
			/* Called to determine the type (if any) of foundation to draw for the house tile */
 
			uint32 callback_res = GetHouseCallback(CBID_HOUSE_DRAW_FOUNDATIONS, 0, 0, house_id, Town::GetByTile(ti->tile), ti->tile);
 
			draw_old_one = (callback_res != 0);
 
			if (callback_res != CALLBACK_FAILED) draw_old_one = ConvertBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DRAW_FOUNDATIONS, callback_res);
 
		}
 

	
 
		if (draw_old_one) DrawFoundation(ti, FOUNDATION_LEVELED);
 
	}
 

	
 
	NewHouseResolver(&object, house_id, ti->tile, Town::GetByTile(ti->tile));
 

	
 
	group = SpriteGroup::Resolve(hs->grf_prop.spritegroup[0], &object);
 
	if (group == NULL || group->type != SGT_TILELAYOUT) {
 
		return;
 
	} else {
 
		/* Limit the building stage to the number of stages supplied. */
 
@@ -543,25 +543,25 @@ void AnimateNewHouseConstruction(TileInd
 
bool CanDeleteHouse(TileIndex tile)
 
{
 
	const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
 

	
 
	/* Humans are always allowed to remove buildings, as is water and
 
	 * anyone using the scenario editor. */
 
	if (Company::IsValidHumanID(_current_company) || _current_company == OWNER_WATER || _current_company == OWNER_NONE) {
 
		return true;
 
	}
 

	
 
	if (HasBit(hs->callback_mask, CBM_HOUSE_DENY_DESTRUCTION)) {
 
		uint16 callback_res = GetHouseCallback(CBID_HOUSE_DENY_DESTRUCTION, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile);
 
		return (callback_res == CALLBACK_FAILED || callback_res == 0);
 
		return (callback_res == CALLBACK_FAILED || !ConvertBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DENY_DESTRUCTION, callback_res));
 
	} else {
 
		return !(hs->extra_flags & BUILDING_IS_PROTECTED);
 
	}
 
}
 

	
 
static void AnimationControl(TileIndex tile, uint16 random_bits)
 
{
 
	const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
 

	
 
	if (HasBit(hs->callback_mask, CBM_HOUSE_ANIMATION_START_STOP)) {
 
		uint32 param = (hs->extra_flags & SYNCHRONISED_CALLBACK_1B) ? (GB(Random(), 0, 16) | random_bits << 16) : Random();
 
		HouseAnimationBase::ChangeAnimationFrame(CBID_HOUSE_ANIMATION_START_STOP, hs, Town::GetByTile(tile), tile, param, 0);
 
@@ -591,25 +591,25 @@ bool NewHouseTileLoop(TileIndex tile)
 
			if (hs->building_flags & BUILDING_HAS_1_TILE)  AnimationControl(tile, random);
 
			if (hs->building_flags & BUILDING_2_TILES_Y)   AnimationControl(TILE_ADDXY(tile, 0, 1), random);
 
			if (hs->building_flags & BUILDING_2_TILES_X)   AnimationControl(TILE_ADDXY(tile, 1, 0), random);
 
			if (hs->building_flags & BUILDING_HAS_4_TILES) AnimationControl(TILE_ADDXY(tile, 1, 1), random);
 
		} else {
 
			AnimationControl(tile, 0);
 
		}
 
	}
 

	
 
	/* Check callback 21, which determines if a house should be destroyed. */
 
	if (HasBit(hs->callback_mask, CBM_HOUSE_DESTRUCTION)) {
 
		uint16 callback_res = GetHouseCallback(CBID_HOUSE_DESTRUCTION, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile);
 
		if (callback_res != CALLBACK_FAILED && GB(callback_res, 0, 8) > 0) {
 
		if (callback_res != CALLBACK_FAILED && Convert8bitBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DESTRUCTION, callback_res)) {
 
			ClearTownHouse(Town::GetByTile(tile), tile);
 
			return false;
 
		}
 
	}
 

	
 
	SetHouseProcessingTime(tile, hs->processing_time);
 
	MarkTileDirtyByTile(tile);
 
	return true;
 
}
 

	
 
static void DoTriggerHouse(TileIndex tile, HouseTrigger trigger, byte base_random, bool first)
 
{
src/newgrf_industries.cpp
Show inline comments
 
@@ -652,16 +652,16 @@ void GetIndustryResolver(ResolverObject 
 
 * @pre cargo_type is in ind->accepts_cargo.
 
 * @return Whether the given industry refuses to accept this cargo type.
 
 */
 
bool IndustryTemporarilyRefusesCargo(Industry *ind, CargoID cargo_type)
 
{
 
	assert(cargo_type == ind->accepts_cargo[0] || cargo_type == ind->accepts_cargo[1] || cargo_type == ind->accepts_cargo[2]);
 

	
 
	const IndustrySpec *indspec = GetIndustrySpec(ind->type);
 
	if (HasBit(indspec->callback_mask, CBM_IND_REFUSE_CARGO)) {
 
		uint16 res = GetIndustryCallback(CBID_INDUSTRY_REFUSE_CARGO,
 
				0, GetReverseCargoTranslation(cargo_type, indspec->grf_prop.grffile),
 
				ind, ind->type, ind->location.tile);
 
		return res == 0;
 
		if (res != CALLBACK_FAILED) return !ConvertBooleanCallback(indspec->grf_prop.grffile, CBID_INDUSTRY_REFUSE_CARGO, res);
 
	}
 
	return false;
 
}
src/newgrf_industrytiles.cpp
Show inline comments
 
@@ -239,25 +239,25 @@ uint16 GetIndustryTileCallback(CallbackI
 
}
 

	
 
bool DrawNewIndustryTile(TileInfo *ti, Industry *i, IndustryGfx gfx, const IndustryTileSpec *inds)
 
{
 
	const SpriteGroup *group;
 
	ResolverObject object;
 

	
 
	if (ti->tileh != SLOPE_FLAT) {
 
		bool draw_old_one = true;
 
		if (HasBit(inds->callback_mask, CBM_INDT_DRAW_FOUNDATIONS)) {
 
			/* Called to determine the type (if any) of foundation to draw for industry tile */
 
			uint32 callback_res = GetIndustryTileCallback(CBID_INDTILE_DRAW_FOUNDATIONS, 0, 0, gfx, i, ti->tile);
 
			draw_old_one = (callback_res != 0);
 
			if (callback_res != CALLBACK_FAILED) draw_old_one = ConvertBooleanCallback(inds->grf_prop.grffile, CBID_INDTILE_DRAW_FOUNDATIONS, callback_res);
 
		}
 

	
 
		if (draw_old_one) DrawFoundation(ti, FOUNDATION_LEVELED);
 
	}
 

	
 
	NewIndustryTileResolver(&object, gfx, ti->tile, i);
 

	
 
	group = SpriteGroup::Resolve(inds->grf_prop.spritegroup[0], &object);
 
	if (group == NULL || group->type != SGT_TILELAYOUT) {
 
		return false;
 
	} else {
 
		/* Limit the building stage to the number of stages supplied. */
src/object_cmd.cpp
Show inline comments
 
@@ -732,25 +732,25 @@ static CommandCost TerraformTile_Object(
 
		 *  - Allow autoslope by default.
 
		 *  - Disallow autoslope if callback succeeds and returns non-zero.
 
		 */
 
		Slope tileh_old = GetTileSlope(tile);
 
		/* TileMaxZ must not be changed. Slopes must not be steep. */
 
		if (!IsSteepSlope(tileh_old) && !IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) {
 
			const ObjectSpec *spec = ObjectSpec::Get(type);
 

	
 
			/* Call callback 'disable autosloping for objects'. */
 
			if (HasBit(spec->callback_mask, CBM_OBJ_AUTOSLOPE)) {
 
				/* If the callback fails, allow autoslope. */
 
				uint16 res = GetObjectCallback(CBID_OBJECT_AUTOSLOPE, 0, 0, spec, Object::GetByTile(tile), tile);
 
				if ((res == 0) || (res == CALLBACK_FAILED)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
 
				if (res == CALLBACK_FAILED || !ConvertBooleanCallback(spec->grf_prop.grffile, CBID_OBJECT_AUTOSLOPE, res)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
 
			} else if (spec->enabled) {
 
				/* allow autoslope */
 
				return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
 
			}
 
		}
 
	}
 

	
 
	return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 
}
 

	
 
extern const TileTypeProcs _tile_type_object_procs = {
 
	DrawTile_Object,             // draw_tile_proc
src/rail_gui.cpp
Show inline comments
 
@@ -58,24 +58,38 @@ struct RailStationGUISettings {
 
	byte station_type;                ///< %Station type within the currently selected custom station class (if newstations is \c true )
 
	byte station_count;               ///< Number of custom stations (if newstations is \c true )
 
};
 
static RailStationGUISettings _railstation; ///< Settings of the station builder GUI
 

	
 

	
 
static void HandleStationPlacement(TileIndex start, TileIndex end);
 
static void ShowBuildTrainDepotPicker(Window *parent);
 
static void ShowBuildWaypointPicker(Window *parent);
 
static void ShowStationBuilder(Window *parent);
 
static void ShowSignalBuilder(Window *parent);
 

	
 
/**
 
 * Check whether a station type can be build.
 
 * @return true if building is allowed.
 
 */
 
static bool IsStationAvailable(const StationSpec *statspec)
 
{
 
	if (statspec == NULL || !HasBit(statspec->callback_mask, CBM_STATION_AVAIL)) return true;
 

	
 
	uint16 cb_res = GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE);
 
	if (cb_res == CALLBACK_FAILED) return true;
 

	
 
	return Convert8bitBooleanCallback(statspec->grf_prop.grffile, CBID_STATION_AVAILABILITY, cb_res);
 
}
 

	
 
void CcPlaySound1E(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
 
{
 
	if (result.Succeeded()) SndPlayTileFx(SND_20_SPLAT_2, tile);
 
}
 

	
 
static void GenericPlaceRail(TileIndex tile, int cmd)
 
{
 
	DoCommandP(tile, _cur_railtype, cmd,
 
			_remove_button_clicked ?
 
			CMD_REMOVE_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) :
 
			CMD_BUILD_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK),
 
			CcPlaySound1E);
 
@@ -1154,26 +1168,25 @@ public:
 
						row++;
 
					}
 
					statclass++;
 
				}
 
				break;
 
			}
 

	
 
			case BRSW_IMAGE: {
 
				byte type = GB(widget, 16, 16);
 
				assert(type < _railstation.station_count);
 
				/* Check station availability callback */
 
				const StationSpec *statspec = StationClass::Get(_railstation.station_class, type);
 
				if (statspec != NULL && HasBit(statspec->callback_mask, CBM_STATION_AVAIL) &&
 
						GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) {
 
				if (!IsStationAvailable(statspec)) {
 
					GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK, FILLRECT_CHECKER);
 
				}
 

	
 
				/* Set up a clipping area for the station preview. */
 
				if (FillDrawPixelInfo(&tmp_dpi, r.left + 1, r.top + 1, r.right - (r.left + 1) + 1, r.bottom - 1 - (r.top + 1) + 1)) {
 
					DrawPixelInfo *old_dpi = _cur_dpi;
 
					_cur_dpi = &tmp_dpi;
 
					if (!DrawStationTile(31, 29, _cur_railtype, _railstation.orientation, _railstation.station_class, type)) {
 
						StationPickerDrawSprite(31, 29, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 2 + _railstation.orientation);
 
					}
 
					_cur_dpi = old_dpi;
 
				}
 
@@ -1349,26 +1362,25 @@ public:
 
					}
 
					y--;
 
				}
 
				break;
 
			}
 

	
 
			case BRSW_IMAGE: {
 
				int y = GB(widget, 16, 16);
 
				if (y >= _railstation.station_count) return;
 

	
 
				/* Check station availability callback */
 
				const StationSpec *statspec = StationClass::Get(_railstation.station_class, y);
 
				if (statspec != NULL && HasBit(statspec->callback_mask, CBM_STATION_AVAIL) &&
 
						GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) return;
 
				if (!IsStationAvailable(statspec)) return;
 

	
 
				_railstation.station_type = y;
 

	
 
				this->CheckSelectedSize(statspec);
 
				this->GetWidget<NWidgetMatrix>(BRSW_MATRIX)->SetClicked(_railstation.station_type);
 

	
 
				SndPlayFx(SND_15_BEEP);
 
				this->SetDirty();
 
				DeleteWindowById(WC_SELECT_STATION, 0);
 
				break;
 
			}
 
		}
 
@@ -1805,45 +1817,41 @@ struct BuildRailWaypointWindow : PickerW
 
				break;
 
		}
 
	}
 

	
 
	virtual void DrawWidget(const Rect &r, int widget) const
 
	{
 
		switch (GB(widget, 0, 16)) {
 
			case BRWW_WAYPOINT: {
 
				byte type = GB(widget, 16, 16);
 
				const StationSpec *statspec = StationClass::Get(STAT_CLASS_WAYP, type);
 
				DrawWaypointSprite(r.left + TILE_PIXELS, r.bottom - TILE_PIXELS, type, _cur_railtype);
 

	
 
				if (statspec != NULL &&
 
						HasBit(statspec->callback_mask, CBM_STATION_AVAIL) &&
 
						GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) {
 
				if (!IsStationAvailable(statspec)) {
 
					GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK, FILLRECT_CHECKER);
 
				}
 
			}
 
		}
 
	}
 

	
 
	virtual void OnClick(Point pt, int widget, int click_count)
 
	{
 
		switch (GB(widget, 0, 16)) {
 
			case BRWW_WAYPOINT: {
 
				byte type = GB(widget, 16, 16);
 
				this->GetWidget<NWidgetMatrix>(BRWW_WAYPOINT_MATRIX)->SetClicked(_cur_waypoint_type);
 

	
 
				/* Check station availability callback */
 
				const StationSpec *statspec = StationClass::Get(STAT_CLASS_WAYP, type);
 
				if (statspec != NULL &&
 
						HasBit(statspec->callback_mask, CBM_STATION_AVAIL) &&
 
						GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) return;
 
				if (!IsStationAvailable(statspec)) return;
 

	
 
				_cur_waypoint_type = type;
 
				this->GetWidget<NWidgetMatrix>(BRWW_WAYPOINT_MATRIX)->SetClicked(_cur_waypoint_type);
 
				SndPlayFx(SND_15_BEEP);
 
				this->SetDirty();
 
				break;
 
			}
 
		}
 
	}
 
};
 

	
 
/** Nested widget definition for the build NewGRF rail waypoint window */
src/station_cmd.cpp
Show inline comments
 
@@ -1178,26 +1178,27 @@ CommandCost CmdBuildRailStation(TileInde
 
	int specindex = AllocateSpecToStation(statspec, st, (flags & DC_EXEC) != 0);
 
	if (specindex == -1) return_cmd_error(STR_ERROR_TOO_MANY_STATION_SPECS);
 

	
 
	if (statspec != NULL) {
 
		/* Perform NewStation checks */
 

	
 
		/* Check if the station size is permitted */
 
		if (HasBit(statspec->disallowed_platforms, numtracks - 1) || HasBit(statspec->disallowed_lengths, plat_len - 1)) {
 
			return CMD_ERROR;
 
		}
 

	
 
		/* Check if the station is buildable */
 
		if (HasBit(statspec->callback_mask, CBM_STATION_AVAIL) && GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) {
 
			return CMD_ERROR;
 
		if (HasBit(statspec->callback_mask, CBM_STATION_AVAIL)) {
 
			uint16 cb_res = GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE);
 
			if (cb_res != CALLBACK_FAILED && !Convert8bitBooleanCallback(statspec->grf_prop.grffile, CBID_STATION_AVAILABILITY, cb_res)) return CMD_ERROR;
 
		}
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		TileIndexDiff tile_delta;
 
		byte *layout_ptr;
 
		byte numtracks_orig;
 
		Track track;
 

	
 
		st->train_station = new_location;
 
		st->AddFacility(FACIL_TRAIN, new_location.tile);
 

	
src/town_cmd.cpp
Show inline comments
 
@@ -264,25 +264,25 @@ static int GetSlopePixelZ_Town(TileIndex
 
static Foundation GetFoundation_Town(TileIndex tile, Slope tileh)
 
{
 
	HouseID hid = GetHouseType(tile);
 

	
 
	/* For NewGRF house tiles we might not be drawing a foundation. We need to
 
	 * account for this, as other structures should
 
	 * draw the wall of the foundation in this case.
 
	 */
 
	if (hid >= NEW_HOUSE_OFFSET) {
 
		const HouseSpec *hs = HouseSpec::Get(hid);
 
		if (hs->grf_prop.spritegroup[0] != NULL && HasBit(hs->callback_mask, CBM_HOUSE_DRAW_FOUNDATIONS)) {
 
			uint32 callback_res = GetHouseCallback(CBID_HOUSE_DRAW_FOUNDATIONS, 0, 0, hid, Town::GetByTile(tile), tile);
 
			if (callback_res == 0) return FOUNDATION_NONE;
 
			if (callback_res != CALLBACK_FAILED && !ConvertBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DRAW_FOUNDATIONS, callback_res)) return FOUNDATION_NONE;
 
		}
 
	}
 
	return FlatteningFoundation(tileh);
 
}
 

	
 
/**
 
 * Animate a tile for a town
 
 * Only certain houses can be animated
 
 * The newhouses animation superseeds regular ones
 
 * @param tile TileIndex of the house to animate
 
 */
 
static void AnimateTile_Town(TileIndex tile)
 
@@ -2198,25 +2198,25 @@ static bool BuildTownHouse(Town *t, Tile
 
		} else if (hs->building_flags & TILE_SIZE_2x1) {
 
			if (!CheckTownBuild2House(&tile, t, maxz, noslope, DIAGDIR_SW)) continue;
 
		} else if (hs->building_flags & TILE_SIZE_1x2) {
 
			if (!CheckTownBuild2House(&tile, t, maxz, noslope, DIAGDIR_SE)) continue;
 
		} else {
 
			/* 1x1 house checks are already done */
 
		}
 

	
 
		byte random_bits = Random();
 

	
 
		if (HasBit(hs->callback_mask, CBM_HOUSE_ALLOW_CONSTRUCTION)) {
 
			uint16 callback_res = GetHouseCallback(CBID_HOUSE_ALLOW_CONSTRUCTION, 0, 0, house, t, tile, true, random_bits);
 
			if (callback_res != CALLBACK_FAILED && GB(callback_res, 0, 8) == 0) continue;
 
			if (callback_res != CALLBACK_FAILED && !Convert8bitBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_ALLOW_CONSTRUCTION, callback_res)) continue;
 
		}
 

	
 
		/* build the house */
 
		t->num_houses++;
 

	
 
		/* Special houses that there can be only one of. */
 
		t->flags |= oneof;
 

	
 
		byte construction_counter = 0;
 
		byte construction_stage = 0;
 

	
 
		if (_generating_world || _game_mode == GM_EDITOR) {
 
@@ -3059,25 +3059,25 @@ static CommandCost TerraformTile_Town(Ti
 

	
 
		/* Here we differ from TTDP by checking TILE_NOT_SLOPED */
 
		if (((hs->building_flags & TILE_NOT_SLOPED) == 0) && !IsSteepSlope(tileh_new) &&
 
				(GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) {
 
			bool allow_terraform = true;
 

	
 
			/* Call the autosloping callback per tile, not for the whole building at once. */
 
			house = GetHouseType(tile);
 
			hs = HouseSpec::Get(house);
 
			if (HasBit(hs->callback_mask, CBM_HOUSE_AUTOSLOPE)) {
 
				/* If the callback fails, allow autoslope. */
 
				uint16 res = GetHouseCallback(CBID_HOUSE_AUTOSLOPE, 0, 0, house, Town::GetByTile(tile), tile);
 
				if ((res != 0) && (res != CALLBACK_FAILED)) allow_terraform = false;
 
				if (res != CALLBACK_FAILED && ConvertBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_AUTOSLOPE, res)) allow_terraform = false;
 
			}
 

	
 
			if (allow_terraform) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
 
		}
 
	}
 

	
 
	return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 
}
 

	
 
/** Tile callback functions for a town */
 
extern const TileTypeProcs _tile_type_town_procs = {
 
	DrawTile_Town,           // draw_tile_proc
0 comments (0 inline, 0 general)