Loading

Revision differences

Old revision #p3hueuoacNew revision #pas0yab3x
1/**  1/**  
2 * Build/Fund an industry  2 * Are the tiles of the industry free?
3 * @param tile tile where industry is built  3 * @param tile                     Position to check.
4 * @param flags of operations to conduct  4 * @param it                       Industry tiles table.
5 * @param p1 various bitstuffed elements  5 * @param itspec_index             The index of the itsepc to build/fund
6 * - p1 = (bit  0 -  7) - industry type see build_industry.h and see industry.h  6 * @param type                     Type of the industry.
7 * - p1 = (bit  8 - 15) - first layout to try  7 * @param initial_random_bits      The random bits the industry is going to have after construction.
8 * - p1 = (bit 16     ) - 0 = prospect, 1 = fund (only valid if current company is DEITY)  8 * @param founder                  Industry founder
9 * @param p2 seed to use for desyncfree randomisations  9 * @param creation_type            The circumstances the industry is created under.
10 * @param text unused  10 * @param [out] custom_shape_check Perform custom check for the site.
11 * @return the cost of this operation or an error  11 * @return Failed or succeeded command.
12 */  12 */  
13CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)  13static CommandCost CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTileTable *it, uint itspec_index, int type, uint16 initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type, bool *custom_shape_check = NULL)
14{  14{  
15    IndustryType it = GB(p1, 0, 8);  15    bool refused_slope = false;
16    if (it >= NUM_INDUSTRYTYPES) return CMD_ERROR;  16    bool custom_shape = false;
17  17  
18    const IndustrySpec *indspec = GetIndustrySpec(it);  18    do {
   19        IndustryGfx gfx = GetTranslatedIndustryTileID(it->gfx);
   20        TileIndex cur_tile = TileAddWrap(tile, it->ti.x, it->ti.y);
19  21  
20    /* Check if the to-be built/founded industry is available for this climate. */  22        if (!IsValidTile(cur_tile)) {
21    if (!indspec->enabled || indspec->num_table == 0) return CMD_ERROR;  23            return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
   24        }
22  25  
23    /* If the setting for raw-material industries is not on, you cannot build raw-material industries.  26        if (gfx == GFX_WATERTILE_SPECIALCHECK) {
24     * Raw material industries are industries that do not accept cargo (at least for now) */  27            if (!IsTileType(cur_tile, MP_WATER) ||
25    if (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 0 && indspec->IsRawIndustry()) {  28                    !IsTileFlat(cur_tile)) {
26        return CMD_ERROR;  29                return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
27    }  30            }
   31        } else {
   32            CommandCost ret = EnsureNoVehicleOnGround(cur_tile);
   33            if (ret.Failed()) return ret;
   34            if (IsBridgeAbove(cur_tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
28  35  
29    if (_game_mode != GM_EDITOR && GetIndustryProbabilityCallback(it, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, 1) == 0) {  29            const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
30        return CMD_ERROR;    
31    }    
32  37  
33    Randomizer randomizer;  33            IndustryBehaviour ind_behav = GetIndustrySpec(type)->behaviour;
34    randomizer.SetSeed(p2);    
35    uint16 random_initial_bits = GB(p2, 0, 16);    
36    uint32 random_var8f = randomizer.Next();    
37    int num_layouts = indspec->num_table;    
38    CommandCost ret = CommandCost(STR_ERROR_SITE_UNSUITABLE);    
39    const bool deity_prospect = _current_company == OWNER_DEITY && !HasBit(p1, 16);    
40  39  
41    Industry *ind = NULL;  40            /* Perform land/water check if not disabled */
42    if (deity_prospect || (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 2 && indspec->IsRawIndustry())) {  41            if (!HasBit(its->slopes_refused, 5) && ((HasTileWaterClass(cur_tile) && IsTileOnWater(cur_tile)) == !(ind_behav & INDUSTRYBEH_BUILT_ONWATER))) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
43        if (flags & DC_EXEC) {  42
44            /* Prospected industries not built on water are built as OWNER_TOWN to not e.g. be build on owned land of the founder */  43            if (HasBit(its->callback_mask, CBM_INDT_SHAPE_CHECK)) {
45            Owner prospector = OWNER_TOWN;  44                custom_shape = true;
46            if ((indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) && _current_company < MAX_COMPANIES) prospector = _current_company;  45                CommandCost ret = PerformIndustryTileSlopeCheck(tile, cur_tile, its, type, gfx, itspec_index, initial_random_bits, founder, creation_type);
47            Backup<CompanyByte> cur_company(_current_company, prospector, FILE_LINE);  46                if (ret.Failed()) return ret;
48            /* Prospecting has a chance to fail, however we cannot guarantee that something can  47            } else {
49             * be built on the map, so the chance gets lower when the map is fuller, but there  48                Slope tileh = GetTileSlope(cur_tile);
50             * is nothing we can really do about that. */  49                refused_slope |= IsSlopeRefused(tileh, its->slopes_refused);
51            if (deity_prospect || Random() <= indspec->prospecting_chance) {  50            }
52                for (int i = 0; i < 5000; i++) {  51
53                    /* We should not have more than one Random() in a function call  52            if ((ind_behav & (INDUSTRYBEH_ONLY_INTOWN | INDUSTRYBEH_TOWN1200_MORE)) || // Tile must be a house
54                     * because parameter evaluation order is not guaranteed in the c++ standard  53                    ((ind_behav & INDUSTRYBEH_ONLY_NEARTOWN) && IsTileType(cur_tile, MP_HOUSE))) { // Tile is allowed to be a house (and it is a house)
55                     */  54                if (!IsTileType(cur_tile, MP_HOUSE)) {
56                    tile = RandomTile();  55                    return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS);
57                    /* Start with a random layout */  56                }
58                    int layout = RandomRange(num_layouts);  57
59                    /* Check now each layout, starting with the random one */  58                /* Clear the tiles as OWNER_TOWN to not affect town rating, and to not clear protected buildings */
60                    for (int j = 0; j < num_layouts; j++) {  59                Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
61                        layout = (layout + 1) % num_layouts;  60                CommandCost ret = DoCommand(cur_tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR);
62                        ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, cur_company.GetOriginalValue(), _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_PROSPECTCREATION, &ind);  61                cur_company.Restore();
63                        if (ret.Succeeded()) break;  62
64                    }  63                if (ret.Failed()) return ret;
65                    if (ret.Succeeded()) break;  64            } else {
   65                /* Clear the tiles, but do not affect town ratings */
   66                CommandCost ret = DoCommand(cur_tile, 0, 0, DC_AUTO | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR);
   67
   68                if (ret.Failed()) {
   69                    if (!(ind_behav & INDUSTRYBEH_BUILT_ONWATER)) return ret;
   70
   71                    if (!_settings_game.construction.build_on_competitor_canal) return ret;
   72                    if (_settings_game.construction.build_on_competitor_canal && (ind_behav & INDUSTRYBEH_BUILT_ONWATER) && (IsTileType(cur_tile, MP_INDUSTRY) || _current_company >= MAX_COMPANIES)) return ret;
66                }  73                }  
67            }  74            }  
68            cur_company.Restore();    
69        }  75        }  
70    } else {  70    } while ((++it)->ti.x != -0x80);
71        int layout = GB(p1, 8, 8);    
72        if (layout >= num_layouts) return CMD_ERROR;    
73  77  
74        /* Check subsequently each layout, starting with the given layout in p1 */  74    if (custom_shape_check != NULL) *custom_shape_check = custom_shape;
75        for (int i = 0; i < num_layouts; i++) {    
76            layout = (layout + 1) % num_layouts;    
77            ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, _current_company, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, &ind);    
78            if (ret.Succeeded()) break;    
79        }    
80  79  
81        /* If it still failed, there's no suitable layout to build here, return the error */  80    /* It is almost impossible to have a fully flat land in TG, so what we
82        if (ret.Failed()) return ret;  81     *  do is that we check if we can make the land flat later on. See
   82     *  CheckIfCanLevelIndustryPlatform(). */
   83    if (!refused_slope || (_settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world && !custom_shape && !_ignore_restrictions)) {
   84        return CommandCost();
83    }  85    }  
84  84    return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
85    if ((flags & DC_EXEC) && ind != NULL && _game_mode != GM_EDITOR) {    
86        AdvertiseIndustryOpening(ind);    
87    }    
88    
89    return CommandCost(EXPENSES_OTHER, indspec->GetConstructionCost());    
90} 87}