From bb8923c336f67270d1c7af12df9c5a9f029d67cc Mon Sep 17 00:00:00 2001 From: rubidium Date: Mon, 9 Jul 2007 13:21:49 +0000 Subject: (svn r10485) -Codechange: add a callback mechanism to determine whether building an industry is allowed at a given location. --- src/industry_cmd.cpp | 28 ++++++++------- src/newgrf_callbacks.h | 2 +- src/newgrf_industries.cpp | 90 +++++++++++++++++++++++++++++++++++++++++++++-- src/newgrf_industries.h | 1 + src/newgrf_spritegroup.h | 5 +++ 5 files changed, 109 insertions(+), 17 deletions(-) diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index 0ba2c0750..60e55a0a6 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -1490,26 +1490,29 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, int type, const Ind * @param type of industry to build * @param flags of operations to conduct * @param indspec pointer to industry specifications - * @param it pointer to list of tile type to build + * @param itspec_index the index of the itsepc to build/fund * @return the pointer of the newly created industry, or NULL if it failed */ -static Industry *CreateNewIndustryHelper(TileIndex tile, IndustryType type, uint32 flags, const IndustrySpec *indspec, const IndustryTileTable *it) +static Industry *CreateNewIndustryHelper(TileIndex tile, IndustryType type, uint32 flags, const IndustrySpec *indspec, uint itspec_index) { - const Town *t; - Industry *i; + const IndustryTileTable *it = indspec->table[itspec_index]; + if (HASBIT(GetIndustrySpec(type)->callback_flags, CBM_IND_LOCATION)) { + if (!CheckIfCallBackAllowsCreation(tile, type, itspec_index)) return NULL; + /* TODO: what with things like quarries and other stuff that must not be on level ground? */ + } if (!CheckIfIndustryTilesAreFree(tile, it, type)) return NULL; if (_patches.land_generator == LG_TERRAGENESIS && _generating_world && !CheckIfCanLevelIndustryPlatform(tile, 0, it, type)) return NULL; if (!_check_new_industry_procs[indspec->check_proc](tile)) return NULL; if (!CheckIfTooCloseToIndustry(tile, type)) return NULL; - t = CheckMultipleIndustryInTown(tile, type); + const Town *t = CheckMultipleIndustryInTown(tile, type); if (t == NULL) return NULL; if (!CheckIfIndustryIsAllowed(tile, type, t)) return NULL; if (!CheckSuitableIndustryPos(tile)) return NULL; - i = AllocateIndustry(); + Industry *i = AllocateIndustry(); if (i == NULL) return NULL; if (flags & DC_EXEC) { @@ -1545,19 +1548,19 @@ CommandCost CmdBuildIndustry(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) /* If the patch for raw-material industries is not on, you cannot build raw-material industries. * Raw material industries are industries that do not accept cargo (at least for now) */ - if (_patches.raw_industry_construction == 0 && indspec->IsRawIndustry()) { + if (_game_mode != GM_EDITOR && _patches.raw_industry_construction == 0 && indspec->IsRawIndustry()) { return CMD_ERROR; } - if (_patches.raw_industry_construction == 2 && indspec->IsRawIndustry()) { + if (_game_mode != GM_EDITOR && _patches.raw_industry_construction == 2 && indspec->IsRawIndustry()) { if (flags & DC_EXEC) { /* Prospecting has a chance to fail, however we cannot guarantee that something can * be built on the map, so the chance gets lower when the map is fuller, but there * is nothing we can really do about that. */ if (Random() <= indspec->prospecting_chance) { for (int i = 0; i < 5000; i++) { - const IndustryTileTable *it = indspec->table[RandomRange(indspec->num_table)]; - const Industry *ind = CreateNewIndustryHelper(RandomTile(), p1, flags, indspec, it); + uint tilespec_index = RandomRange(indspec->num_table); + const Industry *ind = CreateNewIndustryHelper(RandomTile(), p1, flags, indspec, tilespec_index); if (ind != NULL) { SetDParam(0, indspec->name); SetDParam(1, ind->town->index); @@ -1577,7 +1580,7 @@ CommandCost CmdBuildIndustry(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) if (--num < 0) return_cmd_error(STR_0239_SITE_UNSUITABLE); } while (!CheckIfIndustryTilesAreFree(tile, it = itt[num], p1)); - if (CreateNewIndustryHelper(tile, p1, flags, indspec, it) == NULL) return CMD_ERROR; + if (CreateNewIndustryHelper(tile, p1, flags, indspec, num) == NULL) return CMD_ERROR; } return CommandCost(indspec->GetConstructionCost()); @@ -1587,9 +1590,8 @@ CommandCost CmdBuildIndustry(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) Industry *CreateNewIndustry(TileIndex tile, IndustryType type) { const IndustrySpec *indspec = GetIndustrySpec(type); - const IndustryTileTable *it = indspec->table[RandomRange(indspec->num_table)]; - return CreateNewIndustryHelper(tile, type, DC_EXEC, indspec, it); + return CreateNewIndustryHelper(tile, type, DC_EXEC, indspec, RandomRange(indspec->num_table)); } static const byte _numof_industry_table[5][11] = { diff --git a/src/newgrf_callbacks.h b/src/newgrf_callbacks.h index a7ed3e658..bab07c528 100644 --- a/src/newgrf_callbacks.h +++ b/src/newgrf_callbacks.h @@ -97,7 +97,7 @@ enum CallbackID { CBID_INDTILE_ANIMATION_SPEED = 0x27, // not yet implemented /* Called to determine if the given industry can be built on specific area */ - CBID_INDUSTRY_LOCATION = 0x28, // not yet implemented + CBID_INDUSTRY_LOCATION = 0x28, /* Called on production changes, so it can be adjusted */ CBID_INDUSTRY_PRODUCTION_CHANGE = 0x29, // not yet implemented diff --git a/src/newgrf_industries.cpp b/src/newgrf_industries.cpp index 6e43322fb..323143156 100644 --- a/src/newgrf_industries.cpp +++ b/src/newgrf_industries.cpp @@ -7,6 +7,9 @@ #include "debug.h" #include "functions.h" #include "macros.h" +#include "variables.h" +#include "landscape.h" +#include "table/strings.h" #include "industry.h" #include "industry_map.h" #include "newgrf.h" @@ -14,6 +17,8 @@ #include "newgrf_spritegroup.h" #include "newgrf_industries.h" #include "newgrf_commons.h" +#include "newgrf_text.h" +#include "newgrf_town.h" #include "date.h" /* Since the industry IDs defined by the GRF file don't necessarily correlate @@ -116,7 +121,7 @@ uint32 GetIndustryIDAtOffset(TileIndex new_tile, TileIndex old_tile, const Indus uint32 IndustryGetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available) { const Industry *industry = object->u.industry.ind; - TileIndex tile = object->u.industry.tile; + TileIndex tile = object->u.industry.tile; const IndustrySpec *indspec = GetIndustrySpec(industry->type); switch (variable) { @@ -130,8 +135,9 @@ uint32 IndustryGetVariable(const ResolverObject *object, byte variable, byte par return 0; } } - /* TODO: somehow determine whether we're in water or not */ - case 0x43: return GetClosestWaterDistance(tile, true); // Manhattan distance of closes dry/water tile + + /* Manhattan distance of closes dry/water tile */ + case 0x43: return GetClosestWaterDistance(tile, (object->u.industry_location.spec->behaviour & INDUSTRYBEH_BUILT_ONWATER) == 0); /* Get industry ID at offset param */ case 0x60: return GetIndustryIDAtOffset(GetNearbyTile(parameter, industry->xy), tile, industry); @@ -260,6 +266,84 @@ uint16 GetIndustryCallback(uint16 callback, uint32 param1, uint32 param2, Indust return group->g.callback.result; } +uint32 IndustryLocationGetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available) +{ + TileIndex tile = object->u.industry_location.tile; + + if (object->scope == VSG_SCOPE_PARENT) { + return TownGetVariable(variable, parameter, available, ClosestTownFromTile(tile, (uint)-1)); + } + + switch (variable) { + case 0x62: // Land info of nearby tiles + case 0x64: break; // Distance of nearest industry of given type + + /* Location where to build the industry */ + case 0x80: return tile; + case 0x81: return GB(tile, 8, 8); + /* Pointer to the town the industry is associated with */ + case 0x82: return ClosestTownFromTile(tile, (uint)-1)->index; + case 0x83: + case 0x84: + case 0x85: DEBUG(grf, 0, "NewGRFs shouldn't be doing pointer magic"); break; // not supported + + /* Number of the layout */ + case 0x86: return object->u.industry_location.itspec_index; + + /* Ground type */ + case 0x87: return GetTerrainType(tile); + + /* Town zone */ + case 0x88: return GetTownRadiusGroup(ClosestTownFromTile(tile, (uint)-1), tile); + + /* Manhattan distance of the closest town */ + case 0x89: return min(DistanceManhattan(ClosestTownFromTile(tile, (uint)-1)->xy, tile), 255); + + /* Lowest height of the tile */ + case 0x8A: return GetTileZ(tile); + + /* Distance to the nearest water/land tile */ + case 0x8B: return GetClosestWaterDistance(tile, (object->u.industry_location.spec->behaviour & INDUSTRYBEH_BUILT_ONWATER) == 0); + + /* Square of Euclidian distance from town */ + case 0x8D: return min(DistanceSquare(ClosestTownFromTile(tile, (uint)-1)->xy, tile), 65535); + } + + DEBUG(grf, 1, "Unhandled industry property 0x%X", variable); + + *available = false; + return (uint32)-1; +} + +bool CheckIfCallBackAllowsCreation(TileIndex tile, IndustryType type, uint itspec_index) +{ + const IndustrySpec *indspec = GetIndustrySpec(type); + + ResolverObject object; + const SpriteGroup *group; + + NewIndustryResolver(&object, tile, NULL); + object.GetVariable = IndustryLocationGetVariable; + object.callback = CBID_INDUSTRY_LOCATION; + object.u.industry_location.tile = tile; + object.u.industry_location.spec = indspec; + object.u.industry_location.itspec_index = itspec_index; + + group = Resolve(GetIndustrySpec(type)->grf_prop.spritegroup, &object); + + if (group == NULL || group->type != SGT_CALLBACK) return false; + + switch (group->g.callback.result) { + case 0x400: return true; + case 0x401: _error_message = STR_0239_SITE_UNSUITABLE; + case 0x402: _error_message = STR_0317_CAN_ONLY_BE_BUILT_IN_RAINFOREST; + case 0x403: _error_message = STR_0318_CAN_ONLY_BE_BUILT_IN_DESERT; + default: _error_message = GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 + group->g.callback.result); + } + + return false; +} + static int32 DerefIndProd(uint field, bool use_register) { return use_register ? (int32)GetRegister(field) : field; diff --git a/src/newgrf_industries.h b/src/newgrf_industries.h index 0dee9d671..997a9e3f9 100644 --- a/src/newgrf_industries.h +++ b/src/newgrf_industries.h @@ -13,6 +13,7 @@ uint32 IndustryGetVariable(const ResolverObject *object, byte variable, byte par uint16 GetIndustryCallback(uint16 callback, uint32 param1, uint32 param2, Industry *industry, IndustryType type, TileIndex tile); uint32 GetIndustryIDAtOffset(TileIndex new_tile, TileIndex old_tile, const Industry *i); void IndustryProductionCallback(Industry *ind, int reason); +bool CheckIfCallBackAllowsCreation(TileIndex tile, IndustryType type, uint itspec_index); /* in newgrf_industrytiles.cpp*/ uint32 IndustryTileGetRandomBits(const ResolverObject *object); diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h index 02fb1f878..b7bc581d5 100644 --- a/src/newgrf_spritegroup.h +++ b/src/newgrf_spritegroup.h @@ -224,6 +224,11 @@ struct ResolverObject { Industry *ind; IndustryGfx gfx; } industry; + struct { + TileIndex tile; + const IndustrySpec *spec; + uint itspec_index; + } industry_location; struct { const struct CargoSpec *cs; } cargo; -- cgit v1.2.3-54-g00ecf