diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -381,7 +381,7 @@ static Foundation GetFoundation_Industry 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); @@ -1103,9 +1103,14 @@ static void ProduceIndustryGoods(Industr 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); } @@ -1113,9 +1118,16 @@ static void ProduceIndustryGoods(Industr 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); @@ -2734,7 +2746,7 @@ static CommandCost TerraformTile_Industr 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]); diff --git a/src/newgrf_airporttiles.cpp b/src/newgrf_airporttiles.cpp --- a/src/newgrf_airporttiles.cpp +++ b/src/newgrf_airporttiles.cpp @@ -287,7 +287,7 @@ bool DrawNewAirportTile(TileInfo *ti, St 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); diff --git a/src/newgrf_commons.cpp b/src/newgrf_commons.cpp --- a/src/newgrf_commons.cpp +++ b/src/newgrf_commons.cpp @@ -538,6 +538,45 @@ void ErrorUnknownCallbackResult(uint32 g 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 NewGRFSpriteLayout::result_seq; /** diff --git a/src/newgrf_commons.h b/src/newgrf_commons.h --- a/src/newgrf_commons.h +++ b/src/newgrf_commons.h @@ -301,6 +301,8 @@ uint32 GetCompanyInfo(CompanyID owner, c 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. diff --git a/src/newgrf_house.cpp b/src/newgrf_house.cpp --- a/src/newgrf_house.cpp +++ b/src/newgrf_house.cpp @@ -489,7 +489,7 @@ void DrawNewHouseTile(TileInfo *ti, Hous 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); @@ -552,7 +552,7 @@ bool CanDeleteHouse(TileIndex tile) 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); } @@ -600,7 +600,7 @@ bool NewHouseTileLoop(TileIndex tile) /* 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; } diff --git a/src/newgrf_industries.cpp b/src/newgrf_industries.cpp --- a/src/newgrf_industries.cpp +++ b/src/newgrf_industries.cpp @@ -661,7 +661,7 @@ bool IndustryTemporarilyRefusesCargo(Ind 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; } diff --git a/src/newgrf_industrytiles.cpp b/src/newgrf_industrytiles.cpp --- a/src/newgrf_industrytiles.cpp +++ b/src/newgrf_industrytiles.cpp @@ -248,7 +248,7 @@ bool DrawNewIndustryTile(TileInfo *ti, I 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); diff --git a/src/object_cmd.cpp b/src/object_cmd.cpp --- a/src/object_cmd.cpp +++ b/src/object_cmd.cpp @@ -741,7 +741,7 @@ static CommandCost TerraformTile_Object( 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]); diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -67,6 +67,20 @@ static void ShowBuildWaypointPicker(Wind 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); @@ -1163,8 +1177,7 @@ public: 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); } @@ -1358,8 +1371,7 @@ public: /* 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; @@ -1814,9 +1826,7 @@ struct BuildRailWaypointWindow : PickerW 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); } } @@ -1832,9 +1842,7 @@ struct BuildRailWaypointWindow : PickerW /* 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(BRWW_WAYPOINT_MATRIX)->SetClicked(_cur_waypoint_type); diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -1187,8 +1187,9 @@ CommandCost CmdBuildRailStation(TileInde } /* 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; } } diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -273,7 +273,7 @@ static Foundation GetFoundation_Town(Til 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); @@ -2207,7 +2207,7 @@ static bool BuildTownHouse(Town *t, Tile 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 */ @@ -3068,7 +3068,7 @@ static CommandCost TerraformTile_Town(Ti 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]);