Change: Let AI developers edit non-editable AI/Game Script Parameters (#8895)
[openttd-github.git] / src / industry_cmd.cpp
blobb81ba18604e78a1331d52d754491a3b8967c9503
1 /*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
8 /** @file industry_cmd.cpp Handling of industry tiles. */
10 #include "stdafx.h"
11 #include "clear_map.h"
12 #include "industry.h"
13 #include "station_base.h"
14 #include "landscape.h"
15 #include "viewport_func.h"
16 #include "command_func.h"
17 #include "town.h"
18 #include "news_func.h"
19 #include "cheat_type.h"
20 #include "company_base.h"
21 #include "genworld.h"
22 #include "tree_map.h"
23 #include "newgrf_cargo.h"
24 #include "newgrf_debug.h"
25 #include "newgrf_industrytiles.h"
26 #include "autoslope.h"
27 #include "water.h"
28 #include "strings_func.h"
29 #include "window_func.h"
30 #include "date_func.h"
31 #include "vehicle_func.h"
32 #include "sound_func.h"
33 #include "animated_tile_func.h"
34 #include "effectvehicle_func.h"
35 #include "effectvehicle_base.h"
36 #include "ai/ai.hpp"
37 #include "core/pool_func.hpp"
38 #include "subsidy_func.h"
39 #include "core/backup_type.hpp"
40 #include "object_base.h"
41 #include "game/game.hpp"
42 #include "error.h"
43 #include "string_func.h"
44 #include "industry_cmd.h"
45 #include "landscape_cmd.h"
46 #include "terraform_cmd.h"
48 #include "table/strings.h"
49 #include "table/industry_land.h"
50 #include "table/build_industry.h"
52 #include "safeguards.h"
54 IndustryPool _industry_pool("Industry");
55 INSTANTIATE_POOL_METHODS(Industry)
57 void ShowIndustryViewWindow(int industry);
58 void BuildOilRig(TileIndex tile);
60 static byte _industry_sound_ctr;
61 static TileIndex _industry_sound_tile;
63 uint16 Industry::counts[NUM_INDUSTRYTYPES];
65 IndustrySpec _industry_specs[NUM_INDUSTRYTYPES];
66 IndustryTileSpec _industry_tile_specs[NUM_INDUSTRYTILES];
67 IndustryBuildData _industry_builder; ///< In-game manager of industries.
69 /**
70 * This function initialize the spec arrays of both
71 * industry and industry tiles.
72 * It adjusts the enabling of the industry too, based on climate availability.
73 * This will allow for clearer testings
75 void ResetIndustries()
77 for (IndustryType i = 0; i < NUM_INDUSTRYTYPES; i++) {
78 /* Reset the spec to default */
79 if (i < lengthof(_origin_industry_specs)) {
80 _industry_specs[i] = _origin_industry_specs[i];
81 } else {
82 _industry_specs[i] = IndustrySpec{};
85 /* Enable only the current climate industries */
86 _industry_specs[i].enabled = i < NEW_INDUSTRYOFFSET &&
87 HasBit(_origin_industry_specs[i].climate_availability, _settings_game.game_creation.landscape);
90 memset(&_industry_tile_specs, 0, sizeof(_industry_tile_specs));
91 memcpy(&_industry_tile_specs, &_origin_industry_tile_specs, sizeof(_origin_industry_tile_specs));
93 /* Reset any overrides that have been set. */
94 _industile_mngr.ResetOverride();
95 _industry_mngr.ResetOverride();
98 /**
99 * Retrieve the type for this industry. Although it is accessed by a tile,
100 * it will return the general type of industry, and not the sprite index
101 * as would do GetIndustryGfx.
102 * @param tile that is queried
103 * @pre IsTileType(tile, MP_INDUSTRY)
104 * @return general type for this industry, as defined in industry.h
106 IndustryType GetIndustryType(TileIndex tile)
108 assert(IsTileType(tile, MP_INDUSTRY));
110 const Industry *ind = Industry::GetByTile(tile);
111 assert(ind != nullptr);
112 return ind->type;
116 * Accessor for array _industry_specs.
117 * This will ensure at once : proper access and
118 * not allowing modifications of it.
119 * @param thistype of industry (which is the index in _industry_specs)
120 * @pre thistype < NUM_INDUSTRYTYPES
121 * @return a pointer to the corresponding industry spec
123 const IndustrySpec *GetIndustrySpec(IndustryType thistype)
125 assert(thistype < NUM_INDUSTRYTYPES);
126 return &_industry_specs[thistype];
130 * Accessor for array _industry_tile_specs.
131 * This will ensure at once : proper access and
132 * not allowing modifications of it.
133 * @param gfx of industrytile (which is the index in _industry_tile_specs)
134 * @pre gfx < INVALID_INDUSTRYTILE
135 * @return a pointer to the corresponding industrytile spec
137 const IndustryTileSpec *GetIndustryTileSpec(IndustryGfx gfx)
139 assert(gfx < INVALID_INDUSTRYTILE);
140 return &_industry_tile_specs[gfx];
143 Industry::~Industry()
145 if (CleaningPool()) return;
147 /* Industry can also be destroyed when not fully initialized.
148 * This means that we do not have to clear tiles either.
149 * Also we must not decrement industry counts in that case. */
150 if (this->location.w == 0) return;
152 const bool has_neutral_station = this->neutral_station != nullptr;
154 for (TileIndex tile_cur : this->location) {
155 if (IsTileType(tile_cur, MP_INDUSTRY)) {
156 if (GetIndustryIndex(tile_cur) == this->index) {
157 DeleteNewGRFInspectWindow(GSF_INDUSTRYTILES, tile_cur);
159 /* MakeWaterKeepingClass() can also handle 'land' */
160 MakeWaterKeepingClass(tile_cur, OWNER_NONE);
162 } else if (IsTileType(tile_cur, MP_STATION) && IsOilRig(tile_cur)) {
163 DeleteOilRig(tile_cur);
167 if (has_neutral_station) {
168 /* Remove possible docking tiles */
169 for (TileIndex tile_cur : this->location) {
170 ClearDockingTilesCheckingNeighbours(tile_cur);
174 if (GetIndustrySpec(this->type)->behaviour & INDUSTRYBEH_PLANT_FIELDS) {
175 TileArea ta = TileArea(this->location.tile, 0, 0).Expand(21);
177 /* Remove the farmland and convert it to regular tiles over time. */
178 for (TileIndex tile_cur : ta) {
179 if (IsTileType(tile_cur, MP_CLEAR) && IsClearGround(tile_cur, CLEAR_FIELDS) &&
180 GetIndustryIndexOfField(tile_cur) == this->index) {
181 SetIndustryIndexOfField(tile_cur, INVALID_INDUSTRY);
186 /* don't let any disaster vehicle target invalid industry */
187 ReleaseDisastersTargetingIndustry(this->index);
189 /* Clear the persistent storage. */
190 delete this->psa;
192 DecIndustryTypeCount(this->type);
194 DeleteIndustryNews(this->index);
195 CloseWindowById(WC_INDUSTRY_VIEW, this->index);
196 DeleteNewGRFInspectWindow(GSF_INDUSTRIES, this->index);
198 DeleteSubsidyWith(ST_INDUSTRY, this->index);
199 CargoPacket::InvalidateAllFrom(ST_INDUSTRY, this->index);
201 for (Station *st : this->stations_near) {
202 st->RemoveIndustryToDeliver(this);
207 * Invalidating some stuff after removing item from the pool.
208 * @param index index of deleted item
210 void Industry::PostDestructor(size_t index)
212 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, IDIWD_FORCE_REBUILD);
217 * Return a random valid industry.
218 * @return random industry, nullptr if there are no industries
220 /* static */ Industry *Industry::GetRandom()
222 if (Industry::GetNumItems() == 0) return nullptr;
223 int num = RandomRange((uint16)Industry::GetNumItems());
224 size_t index = MAX_UVALUE(size_t);
226 while (num >= 0) {
227 num--;
228 index++;
230 /* Make sure we have a valid industry */
231 while (!Industry::IsValidID(index)) {
232 index++;
233 assert(index < Industry::GetPoolSize());
237 return Industry::Get(index);
241 static void IndustryDrawSugarMine(const TileInfo *ti)
243 if (!IsIndustryCompleted(ti->tile)) return;
245 const DrawIndustryAnimationStruct *d = &_draw_industry_spec1[GetAnimationFrame(ti->tile)];
247 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_SIEVE + d->image_1, PAL_NONE, d->x, 0);
249 if (d->image_2 != 0) {
250 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_CLOUDS + d->image_2 - 1, PAL_NONE, 8, 41);
253 if (d->image_3 != 0) {
254 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_PILE + d->image_3 - 1, PAL_NONE,
255 _drawtile_proc1[d->image_3 - 1].x, _drawtile_proc1[d->image_3 - 1].y);
259 static void IndustryDrawToffeeQuarry(const TileInfo *ti)
261 uint8 x = 0;
263 if (IsIndustryCompleted(ti->tile)) {
264 x = _industry_anim_offs_toffee[GetAnimationFrame(ti->tile)];
265 if (x == 0xFF) {
266 x = 0;
270 AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_SHOVEL, PAL_NONE, 22 - x, 24 + x);
271 AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_TOFFEE, PAL_NONE, 6, 14);
274 static void IndustryDrawBubbleGenerator( const TileInfo *ti)
276 if (IsIndustryCompleted(ti->tile)) {
277 AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_BUBBLE, PAL_NONE, 5, _industry_anim_offs_bubbles[GetAnimationFrame(ti->tile)]);
279 AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_SPRING, PAL_NONE, 3, 67);
282 static void IndustryDrawToyFactory(const TileInfo *ti)
284 const DrawIndustryAnimationStruct *d = &_industry_anim_offs_toys[GetAnimationFrame(ti->tile)];
286 if (d->image_1 != 0xFF) {
287 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_CLAY, PAL_NONE, d->x, 96 + d->image_1);
290 if (d->image_2 != 0xFF) {
291 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_ROBOT, PAL_NONE, 16 - d->image_2 * 2, 100 + d->image_2);
294 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP, PAL_NONE, 7, d->image_3);
295 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP_HOLDER, PAL_NONE, 0, 42);
298 static void IndustryDrawCoalPlantSparks(const TileInfo *ti)
300 if (IsIndustryCompleted(ti->tile)) {
301 uint8 image = GetAnimationFrame(ti->tile);
303 if (image != 0 && image < 7) {
304 AddChildSpriteScreen(image + SPR_IT_POWER_PLANT_TRANSFORMERS,
305 PAL_NONE,
306 _coal_plant_sparks[image - 1].x,
307 _coal_plant_sparks[image - 1].y
313 typedef void IndustryDrawTileProc(const TileInfo *ti);
314 static IndustryDrawTileProc * const _industry_draw_tile_procs[5] = {
315 IndustryDrawSugarMine,
316 IndustryDrawToffeeQuarry,
317 IndustryDrawBubbleGenerator,
318 IndustryDrawToyFactory,
319 IndustryDrawCoalPlantSparks,
322 static void DrawTile_Industry(TileInfo *ti)
324 IndustryGfx gfx = GetIndustryGfx(ti->tile);
325 Industry *ind = Industry::GetByTile(ti->tile);
326 const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
328 /* Retrieve pointer to the draw industry tile struct */
329 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
330 /* Draw the tile using the specialized method of newgrf industrytile.
331 * DrawNewIndustry will return false if ever the resolver could not
332 * find any sprite to display. So in this case, we will jump on the
333 * substitute gfx instead. */
334 if (indts->grf_prop.spritegroup[0] != nullptr && DrawNewIndustryTile(ti, ind, gfx, indts)) {
335 return;
336 } else {
337 /* No sprite group (or no valid one) found, meaning no graphics associated.
338 * Use the substitute one instead */
339 if (indts->grf_prop.subst_id != INVALID_INDUSTRYTILE) {
340 gfx = indts->grf_prop.subst_id;
341 /* And point the industrytile spec accordingly */
342 indts = GetIndustryTileSpec(gfx);
347 const DrawBuildingsTileStruct *dits = &_industry_draw_tile_data[gfx << 2 | (indts->anim_state ?
348 GetAnimationFrame(ti->tile) & INDUSTRY_COMPLETED :
349 GetIndustryConstructionStage(ti->tile))];
351 SpriteID image = dits->ground.sprite;
353 /* DrawFoundation() modifies ti->z and ti->tileh */
354 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
356 /* If the ground sprite is the default flat water sprite, draw also canal/river borders.
357 * Do not do this if the tile's WaterClass is 'land'. */
358 if (image == SPR_FLAT_WATER_TILE && IsTileOnWater(ti->tile)) {
359 DrawWaterClassGround(ti);
360 } else {
361 DrawGroundSprite(image, GroundSpritePaletteTransform(image, dits->ground.pal, GENERAL_SPRITE_COLOUR(ind->random_colour)));
364 /* If industries are transparent and invisible, do not draw the upper part */
365 if (IsInvisibilitySet(TO_INDUSTRIES)) return;
367 /* Add industry on top of the ground? */
368 image = dits->building.sprite;
369 if (image != 0) {
370 AddSortableSpriteToDraw(image, SpriteLayoutPaletteTransform(image, dits->building.pal, GENERAL_SPRITE_COLOUR(ind->random_colour)),
371 ti->x + dits->subtile_x,
372 ti->y + dits->subtile_y,
373 dits->width,
374 dits->height,
375 dits->dz,
376 ti->z,
377 IsTransparencySet(TO_INDUSTRIES));
379 if (IsTransparencySet(TO_INDUSTRIES)) return;
383 int proc = dits->draw_proc - 1;
384 if (proc >= 0) _industry_draw_tile_procs[proc](ti);
388 static int GetSlopePixelZ_Industry(TileIndex tile, uint x, uint y)
390 return GetTileMaxPixelZ(tile);
393 static Foundation GetFoundation_Industry(TileIndex tile, Slope tileh)
395 IndustryGfx gfx = GetIndustryGfx(tile);
397 /* For NewGRF industry tiles we might not be drawing a foundation. We need to
398 * account for this, as other structures should
399 * draw the wall of the foundation in this case.
401 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
402 const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
403 if (indts->grf_prop.spritegroup[0] != nullptr && HasBit(indts->callback_mask, CBM_INDT_DRAW_FOUNDATIONS)) {
404 uint32 callback_res = GetIndustryTileCallback(CBID_INDTILE_DRAW_FOUNDATIONS, 0, 0, gfx, Industry::GetByTile(tile), tile);
405 if (callback_res != CALLBACK_FAILED && !ConvertBooleanCallback(indts->grf_prop.grffile, CBID_INDTILE_DRAW_FOUNDATIONS, callback_res)) return FOUNDATION_NONE;
408 return FlatteningFoundation(tileh);
411 static void AddAcceptedCargo_Industry(TileIndex tile, CargoArray &acceptance, CargoTypes *always_accepted)
413 IndustryGfx gfx = GetIndustryGfx(tile);
414 const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
415 const Industry *ind = Industry::GetByTile(tile);
417 /* Starting point for acceptance */
418 CargoID accepts_cargo[lengthof(itspec->accepts_cargo)];
419 int8 cargo_acceptance[lengthof(itspec->acceptance)];
420 MemCpyT(accepts_cargo, itspec->accepts_cargo, lengthof(accepts_cargo));
421 MemCpyT(cargo_acceptance, itspec->acceptance, lengthof(cargo_acceptance));
423 if (itspec->special_flags & INDTILE_SPECIAL_ACCEPTS_ALL_CARGO) {
424 /* Copy all accepted cargoes from industry itself */
425 for (uint i = 0; i < lengthof(ind->accepts_cargo); i++) {
426 CargoID *pos = std::find(accepts_cargo, endof(accepts_cargo), ind->accepts_cargo[i]);
427 if (pos == endof(accepts_cargo)) {
428 /* Not found, insert */
429 pos = std::find(accepts_cargo, endof(accepts_cargo), CT_INVALID);
430 if (pos == endof(accepts_cargo)) continue; // nowhere to place, give up on this one
431 *pos = ind->accepts_cargo[i];
433 cargo_acceptance[pos - accepts_cargo] += 8;
437 if (HasBit(itspec->callback_mask, CBM_INDT_ACCEPT_CARGO)) {
438 /* Try callback for accepts list, if success override all existing accepts */
439 uint16 res = GetIndustryTileCallback(CBID_INDTILE_ACCEPT_CARGO, 0, 0, gfx, Industry::GetByTile(tile), tile);
440 if (res != CALLBACK_FAILED) {
441 MemSetT(accepts_cargo, CT_INVALID, lengthof(accepts_cargo));
442 for (uint i = 0; i < 3; i++) accepts_cargo[i] = GetCargoTranslation(GB(res, i * 5, 5), itspec->grf_prop.grffile);
446 if (HasBit(itspec->callback_mask, CBM_INDT_CARGO_ACCEPTANCE)) {
447 /* Try callback for acceptance list, if success override all existing acceptance */
448 uint16 res = GetIndustryTileCallback(CBID_INDTILE_CARGO_ACCEPTANCE, 0, 0, gfx, Industry::GetByTile(tile), tile);
449 if (res != CALLBACK_FAILED) {
450 MemSetT(cargo_acceptance, 0, lengthof(cargo_acceptance));
451 for (uint i = 0; i < 3; i++) cargo_acceptance[i] = GB(res, i * 4, 4);
455 for (byte i = 0; i < lengthof(itspec->accepts_cargo); i++) {
456 CargoID a = accepts_cargo[i];
457 if (a == CT_INVALID || cargo_acceptance[i] <= 0) continue; // work only with valid cargoes
459 /* Add accepted cargo */
460 acceptance[a] += cargo_acceptance[i];
462 /* Maybe set 'always accepted' bit (if it's not set already) */
463 if (HasBit(*always_accepted, a)) continue;
465 bool accepts = false;
466 for (uint cargo_index = 0; cargo_index < lengthof(ind->accepts_cargo); cargo_index++) {
467 /* Test whether the industry itself accepts the cargo type */
468 if (ind->accepts_cargo[cargo_index] == a) {
469 accepts = true;
470 break;
474 if (accepts) continue;
476 /* If the industry itself doesn't accept this cargo, set 'always accepted' bit */
477 SetBit(*always_accepted, a);
481 static void GetTileDesc_Industry(TileIndex tile, TileDesc *td)
483 const Industry *i = Industry::GetByTile(tile);
484 const IndustrySpec *is = GetIndustrySpec(i->type);
486 td->owner[0] = i->owner;
487 td->str = is->name;
488 if (!IsIndustryCompleted(tile)) {
489 SetDParamX(td->dparam, 0, td->str);
490 td->str = STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION;
493 if (is->grf_prop.grffile != nullptr) {
494 td->grf = GetGRFConfig(is->grf_prop.grffile->grfid)->GetName();
498 static CommandCost ClearTile_Industry(TileIndex tile, DoCommandFlag flags)
500 Industry *i = Industry::GetByTile(tile);
501 const IndustrySpec *indspec = GetIndustrySpec(i->type);
503 /* water can destroy industries
504 * in editor you can bulldoze industries
505 * with magic_bulldozer cheat you can destroy industries
506 * (area around OILRIG is water, so water shouldn't flood it
508 if ((_current_company != OWNER_WATER && _game_mode != GM_EDITOR &&
509 !_cheats.magic_bulldozer.value) ||
510 ((flags & DC_AUTO) != 0) ||
511 (_current_company == OWNER_WATER &&
512 ((indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) ||
513 HasBit(GetIndustryTileSpec(GetIndustryGfx(tile))->slopes_refused, 5)))) {
514 SetDParam(1, indspec->name);
515 return_cmd_error(flags & DC_AUTO ? STR_ERROR_GENERIC_OBJECT_IN_THE_WAY : INVALID_STRING_ID);
518 if (flags & DC_EXEC) {
519 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index));
520 Game::NewEvent(new ScriptEventIndustryClose(i->index));
521 delete i;
523 return CommandCost(EXPENSES_CONSTRUCTION, indspec->GetRemovalCost());
527 * Move produced cargo from industry to nearby stations.
528 * @param tile Industry tile
529 * @return true if any cargo was moved.
531 static bool TransportIndustryGoods(TileIndex tile)
533 Industry *i = Industry::GetByTile(tile);
534 const IndustrySpec *indspec = GetIndustrySpec(i->type);
535 bool moved_cargo = false;
537 for (uint j = 0; j < lengthof(i->produced_cargo_waiting); j++) {
538 uint cw = std::min<uint>(i->produced_cargo_waiting[j], 255u);
539 if (cw > indspec->minimal_cargo && i->produced_cargo[j] != CT_INVALID) {
540 i->produced_cargo_waiting[j] -= cw;
542 /* fluctuating economy? */
543 if (EconomyIsInRecession()) cw = (cw + 1) / 2;
545 i->this_month_production[j] += cw;
547 uint am = MoveGoodsToStation(i->produced_cargo[j], cw, ST_INDUSTRY, i->index, &i->stations_near, i->exclusive_consumer);
548 i->this_month_transported[j] += am;
550 moved_cargo |= (am != 0);
554 return moved_cargo;
558 static void AnimateTile_Industry(TileIndex tile)
560 IndustryGfx gfx = GetIndustryGfx(tile);
562 if (GetIndustryTileSpec(gfx)->animation.status != ANIM_STATUS_NO_ANIMATION) {
563 AnimateNewIndustryTile(tile);
564 return;
567 switch (gfx) {
568 case GFX_SUGAR_MINE_SIEVE:
569 if ((_tick_counter & 1) == 0) {
570 byte m = GetAnimationFrame(tile) + 1;
572 if (_settings_client.sound.ambient) {
573 switch (m & 7) {
574 case 2: SndPlayTileFx(SND_2D_SUGAR_MINE_1, tile); break;
575 case 6: SndPlayTileFx(SND_29_SUGAR_MINE_2, tile); break;
579 if (m >= 96) {
580 m = 0;
581 DeleteAnimatedTile(tile);
583 SetAnimationFrame(tile, m);
585 MarkTileDirtyByTile(tile);
587 break;
589 case GFX_TOFFEE_QUARY:
590 if ((_tick_counter & 3) == 0) {
591 byte m = GetAnimationFrame(tile);
593 if (_industry_anim_offs_toffee[m] == 0xFF && _settings_client.sound.ambient) {
594 SndPlayTileFx(SND_30_TOFFEE_QUARRY, tile);
597 if (++m >= 70) {
598 m = 0;
599 DeleteAnimatedTile(tile);
601 SetAnimationFrame(tile, m);
603 MarkTileDirtyByTile(tile);
605 break;
607 case GFX_BUBBLE_CATCHER:
608 if ((_tick_counter & 1) == 0) {
609 byte m = GetAnimationFrame(tile);
611 if (++m >= 40) {
612 m = 0;
613 DeleteAnimatedTile(tile);
615 SetAnimationFrame(tile, m);
617 MarkTileDirtyByTile(tile);
619 break;
621 /* Sparks on a coal plant */
622 case GFX_POWERPLANT_SPARKS:
623 if ((_tick_counter & 3) == 0) {
624 byte m = GetAnimationFrame(tile);
625 if (m == 6) {
626 SetAnimationFrame(tile, 0);
627 DeleteAnimatedTile(tile);
628 } else {
629 SetAnimationFrame(tile, m + 1);
630 MarkTileDirtyByTile(tile);
633 break;
635 case GFX_TOY_FACTORY:
636 if ((_tick_counter & 1) == 0) {
637 byte m = GetAnimationFrame(tile) + 1;
639 switch (m) {
640 case 1: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2C_TOY_FACTORY_1, tile); break;
641 case 23: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2B_TOY_FACTORY_2, tile); break;
642 case 28: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2A_TOY_FACTORY_3, tile); break;
643 default:
644 if (m >= 50) {
645 int n = GetIndustryAnimationLoop(tile) + 1;
646 m = 0;
647 if (n >= 8) {
648 n = 0;
649 DeleteAnimatedTile(tile);
651 SetIndustryAnimationLoop(tile, n);
655 SetAnimationFrame(tile, m);
656 MarkTileDirtyByTile(tile);
658 break;
660 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
661 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
662 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
663 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
664 if ((_tick_counter & 3) == 0) {
665 IndustryGfx gfx = GetIndustryGfx(tile);
667 gfx = (gfx < 155) ? gfx + 1 : 148;
668 SetIndustryGfx(tile, gfx);
669 MarkTileDirtyByTile(tile);
671 break;
673 case GFX_OILWELL_ANIMATED_1:
674 case GFX_OILWELL_ANIMATED_2:
675 case GFX_OILWELL_ANIMATED_3:
676 if ((_tick_counter & 7) == 0) {
677 bool b = Chance16(1, 7);
678 IndustryGfx gfx = GetIndustryGfx(tile);
680 byte m = GetAnimationFrame(tile) + 1;
681 if (m == 4 && (m = 0, ++gfx) == GFX_OILWELL_ANIMATED_3 + 1 && (gfx = GFX_OILWELL_ANIMATED_1, b)) {
682 SetIndustryGfx(tile, GFX_OILWELL_NOT_ANIMATED);
683 SetIndustryConstructionStage(tile, 3);
684 DeleteAnimatedTile(tile);
685 } else {
686 SetAnimationFrame(tile, m);
687 SetIndustryGfx(tile, gfx);
688 MarkTileDirtyByTile(tile);
691 break;
693 case GFX_COAL_MINE_TOWER_ANIMATED:
694 case GFX_COPPER_MINE_TOWER_ANIMATED:
695 case GFX_GOLD_MINE_TOWER_ANIMATED: {
696 int state = _tick_counter & 0x7FF;
698 if ((state -= 0x400) < 0) return;
700 if (state < 0x1A0) {
701 if (state < 0x20 || state >= 0x180) {
702 byte m = GetAnimationFrame(tile);
703 if (!(m & 0x40)) {
704 SetAnimationFrame(tile, m | 0x40);
705 if (_settings_client.sound.ambient) SndPlayTileFx(SND_0B_MINE, tile);
707 if (state & 7) return;
708 } else {
709 if (state & 3) return;
711 byte m = (GetAnimationFrame(tile) + 1) | 0x40;
712 if (m > 0xC2) m = 0xC0;
713 SetAnimationFrame(tile, m);
714 MarkTileDirtyByTile(tile);
715 } else if (state >= 0x200 && state < 0x3A0) {
716 int i = (state < 0x220 || state >= 0x380) ? 7 : 3;
717 if (state & i) return;
719 byte m = (GetAnimationFrame(tile) & 0xBF) - 1;
720 if (m < 0x80) m = 0x82;
721 SetAnimationFrame(tile, m);
722 MarkTileDirtyByTile(tile);
724 break;
729 static void CreateChimneySmoke(TileIndex tile)
731 uint x = TileX(tile) * TILE_SIZE;
732 uint y = TileY(tile) * TILE_SIZE;
733 int z = GetTileMaxPixelZ(tile);
735 CreateEffectVehicle(x + 15, y + 14, z + 59, EV_CHIMNEY_SMOKE);
738 static void MakeIndustryTileBigger(TileIndex tile)
740 byte cnt = GetIndustryConstructionCounter(tile) + 1;
741 if (cnt != 4) {
742 SetIndustryConstructionCounter(tile, cnt);
743 return;
746 byte stage = GetIndustryConstructionStage(tile) + 1;
747 SetIndustryConstructionCounter(tile, 0);
748 SetIndustryConstructionStage(tile, stage);
749 StartStopIndustryTileAnimation(tile, IAT_CONSTRUCTION_STATE_CHANGE);
750 if (stage == INDUSTRY_COMPLETED) SetIndustryCompleted(tile);
752 MarkTileDirtyByTile(tile);
754 if (!IsIndustryCompleted(tile)) return;
756 IndustryGfx gfx = GetIndustryGfx(tile);
757 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
758 /* New industries are already animated on construction. */
759 return;
762 switch (gfx) {
763 case GFX_POWERPLANT_CHIMNEY:
764 CreateChimneySmoke(tile);
765 break;
767 case GFX_OILRIG_1: {
768 /* Do not require an industry tile to be after the first two GFX_OILRIG_1
769 * tiles (like the default oil rig). Do a proper check to ensure the
770 * tiles belong to the same industry and based on that build the oil rig's
771 * station. */
772 TileIndex other = tile + TileDiffXY(0, 1);
774 if (IsTileType(other, MP_INDUSTRY) &&
775 GetIndustryGfx(other) == GFX_OILRIG_1 &&
776 GetIndustryIndex(tile) == GetIndustryIndex(other)) {
777 BuildOilRig(tile);
779 break;
782 case GFX_TOY_FACTORY:
783 case GFX_BUBBLE_CATCHER:
784 case GFX_TOFFEE_QUARY:
785 SetAnimationFrame(tile, 0);
786 SetIndustryAnimationLoop(tile, 0);
787 break;
789 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
790 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
791 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
792 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
793 AddAnimatedTile(tile);
794 break;
798 static void TileLoopIndustry_BubbleGenerator(TileIndex tile)
800 static const int8 _bubble_spawn_location[3][4] = {
801 { 11, 0, -4, -14 },
802 { -4, -10, -4, 1 },
803 { 49, 59, 60, 65 },
806 if (_settings_client.sound.ambient) SndPlayTileFx(SND_2E_BUBBLE_GENERATOR, tile);
808 int dir = Random() & 3;
810 EffectVehicle *v = CreateEffectVehicleAbove(
811 TileX(tile) * TILE_SIZE + _bubble_spawn_location[0][dir],
812 TileY(tile) * TILE_SIZE + _bubble_spawn_location[1][dir],
813 _bubble_spawn_location[2][dir],
814 EV_BUBBLE
817 if (v != nullptr) v->animation_substate = dir;
820 static void TileLoop_Industry(TileIndex tile)
822 if (IsTileOnWater(tile)) TileLoop_Water(tile);
824 /* Normally this doesn't happen, but if an industry NewGRF is removed
825 * an industry that was previously build on water can now be flooded.
826 * If this happens the tile is no longer an industry tile after
827 * returning from TileLoop_Water. */
828 if (!IsTileType(tile, MP_INDUSTRY)) return;
830 TriggerIndustryTile(tile, INDTILE_TRIGGER_TILE_LOOP);
832 if (!IsIndustryCompleted(tile)) {
833 MakeIndustryTileBigger(tile);
834 return;
837 if (_game_mode == GM_EDITOR) return;
839 if (TransportIndustryGoods(tile) && !StartStopIndustryTileAnimation(Industry::GetByTile(tile), IAT_INDUSTRY_DISTRIBUTES_CARGO)) {
840 uint newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_production;
842 if (newgfx != INDUSTRYTILE_NOANIM) {
843 ResetIndustryConstructionStage(tile);
844 SetIndustryCompleted(tile);
845 SetIndustryGfx(tile, newgfx);
846 MarkTileDirtyByTile(tile);
847 return;
851 if (StartStopIndustryTileAnimation(tile, IAT_TILELOOP)) return;
853 IndustryGfx newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_next;
854 if (newgfx != INDUSTRYTILE_NOANIM) {
855 ResetIndustryConstructionStage(tile);
856 SetIndustryGfx(tile, newgfx);
857 MarkTileDirtyByTile(tile);
858 return;
861 IndustryGfx gfx = GetIndustryGfx(tile);
862 switch (gfx) {
863 case GFX_COAL_MINE_TOWER_NOT_ANIMATED:
864 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED:
865 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED:
866 if (!(_tick_counter & 0x400) && Chance16(1, 2)) {
867 switch (gfx) {
868 case GFX_COAL_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COAL_MINE_TOWER_ANIMATED; break;
869 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_ANIMATED; break;
870 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_ANIMATED; break;
872 SetIndustryGfx(tile, gfx);
873 SetAnimationFrame(tile, 0x80);
874 AddAnimatedTile(tile);
876 break;
878 case GFX_OILWELL_NOT_ANIMATED:
879 if (Chance16(1, 6)) {
880 SetIndustryGfx(tile, GFX_OILWELL_ANIMATED_1);
881 SetAnimationFrame(tile, 0);
882 AddAnimatedTile(tile);
884 break;
886 case GFX_COAL_MINE_TOWER_ANIMATED:
887 case GFX_COPPER_MINE_TOWER_ANIMATED:
888 case GFX_GOLD_MINE_TOWER_ANIMATED:
889 if (!(_tick_counter & 0x400)) {
890 switch (gfx) {
891 case GFX_COAL_MINE_TOWER_ANIMATED: gfx = GFX_COAL_MINE_TOWER_NOT_ANIMATED; break;
892 case GFX_COPPER_MINE_TOWER_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_NOT_ANIMATED; break;
893 case GFX_GOLD_MINE_TOWER_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_NOT_ANIMATED; break;
895 SetIndustryGfx(tile, gfx);
896 SetIndustryCompleted(tile);
897 SetIndustryConstructionStage(tile, 3);
898 DeleteAnimatedTile(tile);
900 break;
902 case GFX_POWERPLANT_SPARKS:
903 if (Chance16(1, 3)) {
904 if (_settings_client.sound.ambient) SndPlayTileFx(SND_0C_POWER_STATION, tile);
905 AddAnimatedTile(tile);
907 break;
909 case GFX_COPPER_MINE_CHIMNEY:
910 CreateEffectVehicleAbove(TileX(tile) * TILE_SIZE + 6, TileY(tile) * TILE_SIZE + 6, 43, EV_COPPER_MINE_SMOKE);
911 break;
914 case GFX_TOY_FACTORY: {
915 Industry *i = Industry::GetByTile(tile);
916 if (i->was_cargo_delivered) {
917 i->was_cargo_delivered = false;
918 SetIndustryAnimationLoop(tile, 0);
919 AddAnimatedTile(tile);
922 break;
924 case GFX_BUBBLE_GENERATOR:
925 TileLoopIndustry_BubbleGenerator(tile);
926 break;
928 case GFX_TOFFEE_QUARY:
929 AddAnimatedTile(tile);
930 break;
932 case GFX_SUGAR_MINE_SIEVE:
933 if (Chance16(1, 3)) AddAnimatedTile(tile);
934 break;
938 static bool ClickTile_Industry(TileIndex tile)
940 ShowIndustryViewWindow(GetIndustryIndex(tile));
941 return true;
944 static TrackStatus GetTileTrackStatus_Industry(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
946 return 0;
949 static void ChangeTileOwner_Industry(TileIndex tile, Owner old_owner, Owner new_owner)
951 /* If the founder merges, the industry was created by the merged company */
952 Industry *i = Industry::GetByTile(tile);
953 if (i->founder == old_owner) i->founder = (new_owner == INVALID_OWNER) ? OWNER_NONE : new_owner;
955 if (i->exclusive_supplier == old_owner) i->exclusive_supplier = new_owner;
956 if (i->exclusive_consumer == old_owner) i->exclusive_consumer = new_owner;
960 * Check whether the tile is a forest.
961 * @param tile the tile to investigate.
962 * @return true if and only if the tile is a forest
964 bool IsTileForestIndustry(TileIndex tile)
966 /* Check for industry tile */
967 if (!IsTileType(tile, MP_INDUSTRY)) return false;
969 const Industry *ind = Industry::GetByTile(tile);
971 /* Check for organic industry (i.e. not processing or extractive) */
972 if ((GetIndustrySpec(ind->type)->life_type & INDUSTRYLIFE_ORGANIC) == 0) return false;
974 /* Check for wood production */
975 for (uint i = 0; i < lengthof(ind->produced_cargo); i++) {
976 /* The industry produces wood. */
977 if (ind->produced_cargo[i] != CT_INVALID && CargoSpec::Get(ind->produced_cargo[i])->label == 'WOOD') return true;
980 return false;
983 static const byte _plantfarmfield_type[] = {1, 1, 1, 1, 1, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6};
986 * Check whether the tile can be replaced by a farm field.
987 * @param tile the tile to investigate.
988 * @param allow_fields if true, the method will return true even if
989 * the tile is a farm tile, otherwise the tile may not be a farm tile
990 * @return true if the tile can become a farm field
992 static bool IsSuitableForFarmField(TileIndex tile, bool allow_fields)
994 switch (GetTileType(tile)) {
995 case MP_CLEAR: return !IsClearGround(tile, CLEAR_SNOW) && !IsClearGround(tile, CLEAR_DESERT) && (allow_fields || !IsClearGround(tile, CLEAR_FIELDS));
996 case MP_TREES: return GetTreeGround(tile) != TREE_GROUND_SHORE;
997 default: return false;
1002 * Build farm field fence
1003 * @param tile the tile to position the fence on
1004 * @param size the size of the field being planted in tiles
1005 * @param type type of fence to set
1006 * @param side the side of the tile to attempt placement
1008 static void SetupFarmFieldFence(TileIndex tile, int size, byte type, DiagDirection side)
1010 TileIndexDiff diff = (DiagDirToAxis(side) == AXIS_Y ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
1012 do {
1013 tile = TILE_MASK(tile);
1015 if (IsTileType(tile, MP_CLEAR) && IsClearGround(tile, CLEAR_FIELDS)) {
1016 byte or_ = type;
1018 if (or_ == 1 && Chance16(1, 7)) or_ = 2;
1020 SetFence(tile, side, or_);
1023 tile += diff;
1024 } while (--size);
1027 static void PlantFarmField(TileIndex tile, IndustryID industry)
1029 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
1030 if (GetTileZ(tile) + 2 >= GetSnowLine()) return;
1033 /* determine field size */
1034 uint32 r = (Random() & 0x303) + 0x404;
1035 if (_settings_game.game_creation.landscape == LT_ARCTIC) r += 0x404;
1036 uint size_x = GB(r, 0, 8);
1037 uint size_y = GB(r, 8, 8);
1039 TileArea ta(tile - TileDiffXY(std::min(TileX(tile), size_x / 2), std::min(TileY(tile), size_y / 2)), size_x, size_y);
1040 ta.ClampToMap();
1042 if (ta.w == 0 || ta.h == 0) return;
1044 /* check the amount of bad tiles */
1045 int count = 0;
1046 for (TileIndex cur_tile : ta) {
1047 assert(cur_tile < MapSize());
1048 count += IsSuitableForFarmField(cur_tile, false);
1050 if (count * 2 < ta.w * ta.h) return;
1052 /* determine type of field */
1053 r = Random();
1054 uint counter = GB(r, 5, 3);
1055 uint field_type = GB(r, 8, 8) * 9 >> 8;
1057 /* make field */
1058 for (TileIndex cur_tile : ta) {
1059 assert(cur_tile < MapSize());
1060 if (IsSuitableForFarmField(cur_tile, true)) {
1061 MakeField(cur_tile, field_type, industry);
1062 SetClearCounter(cur_tile, counter);
1063 MarkTileDirtyByTile(cur_tile);
1067 int type = 3;
1068 if (_settings_game.game_creation.landscape != LT_ARCTIC && _settings_game.game_creation.landscape != LT_TROPIC) {
1069 type = _plantfarmfield_type[Random() & 0xF];
1072 SetupFarmFieldFence(ta.tile, ta.h, type, DIAGDIR_NE);
1073 SetupFarmFieldFence(ta.tile, ta.w, type, DIAGDIR_NW);
1074 SetupFarmFieldFence(ta.tile + TileDiffXY(ta.w - 1, 0), ta.h, type, DIAGDIR_SW);
1075 SetupFarmFieldFence(ta.tile + TileDiffXY(0, ta.h - 1), ta.w, type, DIAGDIR_SE);
1078 void PlantRandomFarmField(const Industry *i)
1080 int x = i->location.w / 2 + Random() % 31 - 16;
1081 int y = i->location.h / 2 + Random() % 31 - 16;
1083 TileIndex tile = TileAddWrap(i->location.tile, x, y);
1085 if (tile != INVALID_TILE) PlantFarmField(tile, i->index);
1089 * Search callback function for ChopLumberMillTrees
1090 * @param tile to test
1091 * @param user_data that is passed by the caller. In this case, nothing
1092 * @return the result of the test
1094 static bool SearchLumberMillTrees(TileIndex tile, void *user_data)
1096 if (IsTileType(tile, MP_TREES) && GetTreeGrowth(tile) > 2) { ///< 3 and up means all fully grown trees
1097 /* found a tree */
1099 Backup<CompanyID> cur_company(_current_company, OWNER_NONE, FILE_LINE);
1101 _industry_sound_ctr = 1;
1102 _industry_sound_tile = tile;
1103 if (_settings_client.sound.ambient) SndPlayTileFx(SND_38_LUMBER_MILL_1, tile);
1105 Command<CMD_LANDSCAPE_CLEAR>::Do(DC_EXEC, tile);
1107 cur_company.Restore();
1108 return true;
1110 return false;
1114 * Perform a circular search around the Lumber Mill in order to find trees to cut
1115 * @param i industry
1117 static void ChopLumberMillTrees(Industry *i)
1119 /* We only want to cut trees if all tiles are completed. */
1120 for (TileIndex tile_cur : i->location) {
1121 if (i->TileBelongsToIndustry(tile_cur)) {
1122 if (!IsIndustryCompleted(tile_cur)) return;
1126 TileIndex tile = i->location.tile;
1127 if (CircularTileSearch(&tile, 40, SearchLumberMillTrees, nullptr)) { // 40x40 tiles to search.
1128 i->produced_cargo_waiting[0] = std::min(0xffff, i->produced_cargo_waiting[0] + 45); // Found a tree, add according value to waiting cargo.
1132 static void ProduceIndustryGoods(Industry *i)
1134 const IndustrySpec *indsp = GetIndustrySpec(i->type);
1136 /* play a sound? */
1137 if ((i->counter & 0x3F) == 0) {
1138 uint32 r;
1139 if (Chance16R(1, 14, r) && indsp->number_of_sounds != 0 && _settings_client.sound.ambient) {
1140 for (size_t j = 0; j < lengthof(i->last_month_production); j++) {
1141 if (i->last_month_production[j] > 0) {
1142 /* Play sound since last month had production */
1143 SndPlayTileFx(
1144 (SoundFx)(indsp->random_sounds[((r >> 16) * indsp->number_of_sounds) >> 16]),
1145 i->location.tile);
1146 break;
1152 i->counter--;
1154 /* produce some cargo */
1155 if ((i->counter % INDUSTRY_PRODUCE_TICKS) == 0) {
1156 if (HasBit(indsp->callback_mask, CBM_IND_PRODUCTION_256_TICKS)) IndustryProductionCallback(i, 1);
1158 IndustryBehaviour indbehav = indsp->behaviour;
1159 for (size_t j = 0; j < lengthof(i->produced_cargo_waiting); j++) {
1160 i->produced_cargo_waiting[j] = std::min(0xffff, i->produced_cargo_waiting[j] + i->production_rate[j]);
1163 if ((indbehav & INDUSTRYBEH_PLANT_FIELDS) != 0) {
1164 uint16 cb_res = CALLBACK_FAILED;
1165 if (HasBit(indsp->callback_mask, CBM_IND_SPECIAL_EFFECT)) {
1166 cb_res = GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 0, i, i->type, i->location.tile);
1169 bool plant;
1170 if (cb_res != CALLBACK_FAILED) {
1171 plant = ConvertBooleanCallback(indsp->grf_prop.grffile, CBID_INDUSTRY_SPECIAL_EFFECT, cb_res);
1172 } else {
1173 plant = Chance16(1, 8);
1176 if (plant) PlantRandomFarmField(i);
1178 if ((indbehav & INDUSTRYBEH_CUT_TREES) != 0) {
1179 uint16 cb_res = CALLBACK_FAILED;
1180 if (HasBit(indsp->callback_mask, CBM_IND_SPECIAL_EFFECT)) {
1181 cb_res = GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 1, i, i->type, i->location.tile);
1184 bool cut;
1185 if (cb_res != CALLBACK_FAILED) {
1186 cut = ConvertBooleanCallback(indsp->grf_prop.grffile, CBID_INDUSTRY_SPECIAL_EFFECT, cb_res);
1187 } else {
1188 cut = ((i->counter % INDUSTRY_CUT_TREE_TICKS) == 0);
1191 if (cut) ChopLumberMillTrees(i);
1194 TriggerIndustry(i, INDUSTRY_TRIGGER_INDUSTRY_TICK);
1195 StartStopIndustryTileAnimation(i, IAT_INDUSTRY_TICK);
1199 void OnTick_Industry()
1201 if (_industry_sound_ctr != 0) {
1202 _industry_sound_ctr++;
1204 if (_industry_sound_ctr == 75) {
1205 if (_settings_client.sound.ambient) SndPlayTileFx(SND_37_LUMBER_MILL_2, _industry_sound_tile);
1206 } else if (_industry_sound_ctr == 160) {
1207 _industry_sound_ctr = 0;
1208 if (_settings_client.sound.ambient) SndPlayTileFx(SND_36_LUMBER_MILL_3, _industry_sound_tile);
1212 if (_game_mode == GM_EDITOR) return;
1214 for (Industry *i : Industry::Iterate()) {
1215 ProduceIndustryGoods(i);
1220 * Check the conditions of #CHECK_NOTHING (Always succeeds).
1221 * @param tile %Tile to perform the checking.
1222 * @return Succeeded or failed command.
1224 static CommandCost CheckNewIndustry_NULL(TileIndex tile)
1226 return CommandCost();
1230 * Check the conditions of #CHECK_FOREST (Industry should be build above snow-line in arctic climate).
1231 * @param tile %Tile to perform the checking.
1232 * @return Succeeded or failed command.
1234 static CommandCost CheckNewIndustry_Forest(TileIndex tile)
1236 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
1237 if (GetTileZ(tile) < HighestSnowLine() + 2) {
1238 return_cmd_error(STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED);
1241 return CommandCost();
1245 * Check if a tile is within a distance from map edges, scaled by map dimensions independently.
1246 * Each dimension is checked independently, and dimensions smaller than 256 are not scaled.
1247 * @param tile Which tile to check distance of.
1248 * @param maxdist Normal distance on a 256x256 map.
1249 * @return True if the tile is near the map edge.
1251 static bool CheckScaledDistanceFromEdge(TileIndex tile, uint maxdist)
1253 uint maxdist_x = maxdist;
1254 uint maxdist_y = maxdist;
1256 if (MapSizeX() > 256) maxdist_x *= MapSizeX() / 256;
1257 if (MapSizeY() > 256) maxdist_y *= MapSizeY() / 256;
1259 if (DistanceFromEdgeDir(tile, DIAGDIR_NE) < maxdist_x) return true;
1260 if (DistanceFromEdgeDir(tile, DIAGDIR_NW) < maxdist_y) return true;
1261 if (DistanceFromEdgeDir(tile, DIAGDIR_SW) < maxdist_x) return true;
1262 if (DistanceFromEdgeDir(tile, DIAGDIR_SE) < maxdist_y) return true;
1264 return false;
1268 * Check the conditions of #CHECK_REFINERY (Industry should be positioned near edge of the map).
1269 * @param tile %Tile to perform the checking.
1270 * @return Succeeded or failed command.
1272 static CommandCost CheckNewIndustry_OilRefinery(TileIndex tile)
1274 if (_game_mode == GM_EDITOR) return CommandCost();
1276 if (CheckScaledDistanceFromEdge(TILE_ADDXY(tile, 1, 1), _settings_game.game_creation.oil_refinery_limit)) return CommandCost();
1278 return_cmd_error(STR_ERROR_CAN_ONLY_BE_POSITIONED);
1281 extern bool _ignore_restrictions;
1284 * Check the conditions of #CHECK_OIL_RIG (Industries at sea should be positioned near edge of the map).
1285 * @param tile %Tile to perform the checking.
1286 * @return Succeeded or failed command.
1288 static CommandCost CheckNewIndustry_OilRig(TileIndex tile)
1290 if (_game_mode == GM_EDITOR && _ignore_restrictions) return CommandCost();
1292 if (TileHeight(tile) == 0 &&
1293 CheckScaledDistanceFromEdge(TILE_ADDXY(tile, 1, 1), _settings_game.game_creation.oil_refinery_limit)) return CommandCost();
1295 return_cmd_error(STR_ERROR_CAN_ONLY_BE_POSITIONED);
1299 * Check the conditions of #CHECK_FARM (Industry should be below snow-line in arctic).
1300 * @param tile %Tile to perform the checking.
1301 * @return Succeeded or failed command.
1303 static CommandCost CheckNewIndustry_Farm(TileIndex tile)
1305 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
1306 if (GetTileZ(tile) + 2 >= HighestSnowLine()) {
1307 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1310 return CommandCost();
1314 * Check the conditions of #CHECK_PLANTATION (Industry should NOT be in the desert).
1315 * @param tile %Tile to perform the checking.
1316 * @return Succeeded or failed command.
1318 static CommandCost CheckNewIndustry_Plantation(TileIndex tile)
1320 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
1321 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1323 return CommandCost();
1327 * Check the conditions of #CHECK_WATER (Industry should be in the desert).
1328 * @param tile %Tile to perform the checking.
1329 * @return Succeeded or failed command.
1331 static CommandCost CheckNewIndustry_Water(TileIndex tile)
1333 if (GetTropicZone(tile) != TROPICZONE_DESERT) {
1334 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT);
1336 return CommandCost();
1340 * Check the conditions of #CHECK_LUMBERMILL (Industry should be in the rain forest).
1341 * @param tile %Tile to perform the checking.
1342 * @return Succeeded or failed command.
1344 static CommandCost CheckNewIndustry_Lumbermill(TileIndex tile)
1346 if (GetTropicZone(tile) != TROPICZONE_RAINFOREST) {
1347 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST);
1349 return CommandCost();
1353 * Check the conditions of #CHECK_BUBBLEGEN (Industry should be in low land).
1354 * @param tile %Tile to perform the checking.
1355 * @return Succeeded or failed command.
1357 static CommandCost CheckNewIndustry_BubbleGen(TileIndex tile)
1359 if (GetTileZ(tile) > 4) {
1360 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS);
1362 return CommandCost();
1366 * Industrytype check function signature.
1367 * @param tile %Tile to check.
1368 * @return Succeeded or failed command.
1370 typedef CommandCost CheckNewIndustryProc(TileIndex tile);
1372 /** Check functions for different types of industry. */
1373 static CheckNewIndustryProc * const _check_new_industry_procs[CHECK_END] = {
1374 CheckNewIndustry_NULL, ///< CHECK_NOTHING
1375 CheckNewIndustry_Forest, ///< CHECK_FOREST
1376 CheckNewIndustry_OilRefinery, ///< CHECK_REFINERY
1377 CheckNewIndustry_Farm, ///< CHECK_FARM
1378 CheckNewIndustry_Plantation, ///< CHECK_PLANTATION
1379 CheckNewIndustry_Water, ///< CHECK_WATER
1380 CheckNewIndustry_Lumbermill, ///< CHECK_LUMBERMILL
1381 CheckNewIndustry_BubbleGen, ///< CHECK_BUBBLEGEN
1382 CheckNewIndustry_OilRig, ///< CHECK_OIL_RIG
1386 * Find a town for the industry, while checking for multiple industries in the same town.
1387 * @param tile Position of the industry to build.
1388 * @param type Industry type.
1389 * @param[out] t Pointer to return town for the new industry, \c nullptr is written if no good town can be found.
1390 * @return Succeeded or failed command.
1392 * @pre \c *t != nullptr
1393 * @post \c *t points to a town on success, and \c nullptr on failure.
1395 static CommandCost FindTownForIndustry(TileIndex tile, int type, Town **t)
1397 *t = ClosestTownFromTile(tile, UINT_MAX);
1399 if (_settings_game.economy.multiple_industry_per_town) return CommandCost();
1401 for (const Industry *i : Industry::Iterate()) {
1402 if (i->type == (byte)type && i->town == *t) {
1403 *t = nullptr;
1404 return_cmd_error(STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN);
1408 return CommandCost();
1411 bool IsSlopeRefused(Slope current, Slope refused)
1413 if (IsSteepSlope(current)) return true;
1414 if (current != SLOPE_FLAT) {
1415 if (IsSteepSlope(refused)) return true;
1417 Slope t = ComplementSlope(current);
1419 if ((refused & SLOPE_W) && (t & SLOPE_NW)) return true;
1420 if ((refused & SLOPE_S) && (t & SLOPE_NE)) return true;
1421 if ((refused & SLOPE_E) && (t & SLOPE_SW)) return true;
1422 if ((refused & SLOPE_N) && (t & SLOPE_SE)) return true;
1425 return false;
1429 * Are the tiles of the industry free?
1430 * @param tile Position to check.
1431 * @param layout Industry tiles table.
1432 * @param type Type of the industry.
1433 * @return Failed or succeeded command.
1435 static CommandCost CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTileLayout &layout, IndustryType type)
1437 IndustryBehaviour ind_behav = GetIndustrySpec(type)->behaviour;
1439 for (const IndustryTileLayoutTile &it : layout) {
1440 IndustryGfx gfx = GetTranslatedIndustryTileID(it.gfx);
1441 TileIndex cur_tile = TileAddWrap(tile, it.ti.x, it.ti.y);
1443 if (!IsValidTile(cur_tile)) {
1444 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1447 if (gfx == GFX_WATERTILE_SPECIALCHECK) {
1448 if (!IsWaterTile(cur_tile) ||
1449 !IsTileFlat(cur_tile)) {
1450 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1452 } else {
1453 CommandCost ret = EnsureNoVehicleOnGround(cur_tile);
1454 if (ret.Failed()) return ret;
1455 if (IsBridgeAbove(cur_tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1457 const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
1459 /* Perform land/water check if not disabled */
1460 if (!HasBit(its->slopes_refused, 5) && ((HasTileWaterClass(cur_tile) && IsTileOnWater(cur_tile)) == !(ind_behav & INDUSTRYBEH_BUILT_ONWATER))) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1462 if ((ind_behav & (INDUSTRYBEH_ONLY_INTOWN | INDUSTRYBEH_TOWN1200_MORE)) || // Tile must be a house
1463 ((ind_behav & INDUSTRYBEH_ONLY_NEARTOWN) && IsTileType(cur_tile, MP_HOUSE))) { // Tile is allowed to be a house (and it is a house)
1464 if (!IsTileType(cur_tile, MP_HOUSE)) {
1465 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS);
1468 /* Clear the tiles as OWNER_TOWN to not affect town rating, and to not clear protected buildings */
1469 Backup<CompanyID> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
1470 CommandCost ret = Command<CMD_LANDSCAPE_CLEAR>::Do(DC_NONE, cur_tile);
1471 cur_company.Restore();
1473 if (ret.Failed()) return ret;
1474 } else {
1475 /* Clear the tiles, but do not affect town ratings */
1476 CommandCost ret = Command<CMD_LANDSCAPE_CLEAR>::Do(DC_AUTO | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, cur_tile);
1477 if (ret.Failed()) return ret;
1482 return CommandCost();
1486 * Check slope requirements for industry tiles.
1487 * @param tile Position to check.
1488 * @param layout Industry tiles table.
1489 * @param layout_index The index of the layout to build/fund
1490 * @param type Type of the industry.
1491 * @param initial_random_bits The random bits the industry is going to have after construction.
1492 * @param founder Industry founder
1493 * @param creation_type The circumstances the industry is created under.
1494 * @param[out] custom_shape_check Perform custom check for the site.
1495 * @return Failed or succeeded command.
1497 static CommandCost CheckIfIndustryTileSlopes(TileIndex tile, const IndustryTileLayout &layout, size_t layout_index, int type, uint16 initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type, bool *custom_shape_check = nullptr)
1499 bool refused_slope = false;
1500 bool custom_shape = false;
1502 for (const IndustryTileLayoutTile &it : layout) {
1503 IndustryGfx gfx = GetTranslatedIndustryTileID(it.gfx);
1504 TileIndex cur_tile = TileAddWrap(tile, it.ti.x, it.ti.y);
1505 assert(IsValidTile(cur_tile)); // checked before in CheckIfIndustryTilesAreFree
1507 if (gfx != GFX_WATERTILE_SPECIALCHECK) {
1508 const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
1510 if (HasBit(its->callback_mask, CBM_INDT_SHAPE_CHECK)) {
1511 custom_shape = true;
1512 CommandCost ret = PerformIndustryTileSlopeCheck(tile, cur_tile, its, type, gfx, layout_index, initial_random_bits, founder, creation_type);
1513 if (ret.Failed()) return ret;
1514 } else {
1515 Slope tileh = GetTileSlope(cur_tile);
1516 refused_slope |= IsSlopeRefused(tileh, its->slopes_refused);
1521 if (custom_shape_check != nullptr) *custom_shape_check = custom_shape;
1523 /* It is almost impossible to have a fully flat land in TG, so what we
1524 * do is that we check if we can make the land flat later on. See
1525 * CheckIfCanLevelIndustryPlatform(). */
1526 if (!refused_slope || (_settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world && !custom_shape && !_ignore_restrictions)) {
1527 return CommandCost();
1529 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1533 * Is the industry allowed to be built at this place for the town?
1534 * @param tile Tile to construct the industry.
1535 * @param type Type of the industry.
1536 * @param t Town authority that the industry belongs to.
1537 * @return Succeeded or failed command.
1539 static CommandCost CheckIfIndustryIsAllowed(TileIndex tile, int type, const Town *t)
1541 if ((GetIndustrySpec(type)->behaviour & INDUSTRYBEH_TOWN1200_MORE) && t->cache.population < 1200) {
1542 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200);
1545 if ((GetIndustrySpec(type)->behaviour & INDUSTRYBEH_ONLY_NEARTOWN) && DistanceMax(t->xy, tile) > 9) {
1546 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER);
1549 return CommandCost();
1552 static bool CheckCanTerraformSurroundingTiles(TileIndex tile, uint height, int internal)
1554 /* Check if we don't leave the map */
1555 if (TileX(tile) == 0 || TileY(tile) == 0 || GetTileType(tile) == MP_VOID) return false;
1557 TileArea ta(tile - TileDiffXY(1, 1), 2, 2);
1558 for (TileIndex tile_walk : ta) {
1559 uint curh = TileHeight(tile_walk);
1560 /* Is the tile clear? */
1561 if ((GetTileType(tile_walk) != MP_CLEAR) && (GetTileType(tile_walk) != MP_TREES)) return false;
1563 /* Don't allow too big of a change if this is the sub-tile check */
1564 if (internal != 0 && Delta(curh, height) > 1) return false;
1566 /* Different height, so the surrounding tiles of this tile
1567 * has to be correct too (in level, or almost in level)
1568 * else you get a chain-reaction of terraforming. */
1569 if (internal == 0 && curh != height) {
1570 if (TileX(tile_walk) == 0 || TileY(tile_walk) == 0 || !CheckCanTerraformSurroundingTiles(tile_walk + TileDiffXY(-1, -1), height, internal + 1)) {
1571 return false;
1576 return true;
1580 * This function tries to flatten out the land below an industry, without
1581 * damaging the surroundings too much.
1583 static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, DoCommandFlag flags, const IndustryTileLayout &layout, int type)
1585 int max_x = 0;
1586 int max_y = 0;
1588 /* Finds dimensions of largest variant of this industry */
1589 for (const IndustryTileLayoutTile &it : layout) {
1590 if (it.gfx == GFX_WATERTILE_SPECIALCHECK) continue; // watercheck tiles don't count for footprint size
1591 if (it.ti.x > max_x) max_x = it.ti.x;
1592 if (it.ti.y > max_y) max_y = it.ti.y;
1595 /* Remember level height */
1596 uint h = TileHeight(tile);
1598 if (TileX(tile) <= _settings_game.construction.industry_platform + 1U || TileY(tile) <= _settings_game.construction.industry_platform + 1U) return false;
1599 /* Check that all tiles in area and surrounding are clear
1600 * this determines that there are no obstructing items */
1602 /* TileArea::Expand is not used here as we need to abort
1603 * instead of clamping if the bounds cannot expanded. */
1604 TileArea ta(tile + TileDiffXY(-_settings_game.construction.industry_platform, -_settings_game.construction.industry_platform),
1605 max_x + 2 + 2 * _settings_game.construction.industry_platform, max_y + 2 + 2 * _settings_game.construction.industry_platform);
1607 if (TileX(ta.tile) + ta.w >= MapMaxX() || TileY(ta.tile) + ta.h >= MapMaxY()) return false;
1609 /* _current_company is OWNER_NONE for randomly generated industries and in editor, or the company who funded or prospected the industry.
1610 * Perform terraforming as OWNER_TOWN to disable autoslope and town ratings. */
1611 Backup<CompanyID> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
1613 for (TileIndex tile_walk : ta) {
1614 uint curh = TileHeight(tile_walk);
1615 if (curh != h) {
1616 /* This tile needs terraforming. Check if we can do that without
1617 * damaging the surroundings too much. */
1618 if (!CheckCanTerraformSurroundingTiles(tile_walk, h, 0)) {
1619 cur_company.Restore();
1620 return false;
1622 /* This is not 100% correct check, but the best we can do without modifying the map.
1623 * What is missing, is if the difference in height is more than 1.. */
1624 if (std::get<0>(Command<CMD_TERRAFORM_LAND>::Do(flags & ~DC_EXEC, tile_walk, SLOPE_N, curh <= h)).Failed()) {
1625 cur_company.Restore();
1626 return false;
1631 if (flags & DC_EXEC) {
1632 /* Terraform the land under the industry */
1633 for (TileIndex tile_walk : ta) {
1634 uint curh = TileHeight(tile_walk);
1635 while (curh != h) {
1636 /* We give the terraforming for free here, because we can't calculate
1637 * exact cost in the test-round, and as we all know, that will cause
1638 * a nice assert if they don't match ;) */
1639 Command<CMD_TERRAFORM_LAND>::Do(flags, tile_walk, SLOPE_N, curh <= h);
1640 curh += (curh > h) ? -1 : 1;
1645 cur_company.Restore();
1646 return true;
1651 * Check that the new industry is far enough from conflicting industries.
1652 * @param tile Tile to construct the industry.
1653 * @param type Type of the new industry.
1654 * @return Succeeded or failed command.
1656 static CommandCost CheckIfFarEnoughFromConflictingIndustry(TileIndex tile, int type)
1658 const IndustrySpec *indspec = GetIndustrySpec(type);
1660 /* On a large map with many industries, it may be faster to check an area. */
1661 static const int dmax = 14;
1662 if (Industry::GetNumItems() > (size_t) (dmax * dmax * 2)) {
1663 const Industry* i = nullptr;
1664 TileArea tile_area = TileArea(tile, 1, 1).Expand(dmax);
1665 for (TileIndex atile : tile_area) {
1666 if (GetTileType(atile) == MP_INDUSTRY) {
1667 const Industry *i2 = Industry::GetByTile(atile);
1668 if (i == i2) continue;
1669 i = i2;
1670 if (DistanceMax(tile, i->location.tile) > (uint)dmax) continue;
1671 if (i->type == indspec->conflicting[0] ||
1672 i->type == indspec->conflicting[1] ||
1673 i->type == indspec->conflicting[2]) {
1674 return_cmd_error(STR_ERROR_INDUSTRY_TOO_CLOSE);
1678 return CommandCost();
1681 for (const Industry *i : Industry::Iterate()) {
1682 /* Within 14 tiles from another industry is considered close */
1683 if (DistanceMax(tile, i->location.tile) > 14) continue;
1685 /* check if there are any conflicting industry types around */
1686 if (i->type == indspec->conflicting[0] ||
1687 i->type == indspec->conflicting[1] ||
1688 i->type == indspec->conflicting[2]) {
1689 return_cmd_error(STR_ERROR_INDUSTRY_TOO_CLOSE);
1692 return CommandCost();
1696 * Advertise about a new industry opening.
1697 * @param ind Industry being opened.
1699 static void AdvertiseIndustryOpening(const Industry *ind)
1701 const IndustrySpec *ind_spc = GetIndustrySpec(ind->type);
1702 SetDParam(0, ind_spc->name);
1703 if (ind_spc->new_industry_text > STR_LAST_STRINGID) {
1704 SetDParam(1, STR_TOWN_NAME);
1705 SetDParam(2, ind->town->index);
1706 } else {
1707 SetDParam(1, ind->town->index);
1709 AddIndustryNewsItem(ind_spc->new_industry_text, NT_INDUSTRY_OPEN, ind->index);
1710 AI::BroadcastNewEvent(new ScriptEventIndustryOpen(ind->index));
1711 Game::NewEvent(new ScriptEventIndustryOpen(ind->index));
1715 * Populate an industry's list of nearby stations, and if it accepts any cargo, also
1716 * add the industry to each station's nearby industry list.
1717 * @param ind Industry
1719 static void PopulateStationsNearby(Industry *ind)
1721 if (ind->neutral_station != nullptr && !_settings_game.station.serve_neutral_industries) {
1722 /* Industry has a neutral station. Use it and ignore any other nearby stations. */
1723 ind->stations_near.insert(ind->neutral_station);
1724 ind->neutral_station->industries_near.clear();
1725 ind->neutral_station->industries_near.insert(IndustryListEntry{0, ind});
1726 return;
1729 ForAllStationsAroundTiles(ind->location, [ind](Station *st, TileIndex tile) {
1730 if (!IsTileType(tile, MP_INDUSTRY) || GetIndustryIndex(tile) != ind->index) return false;
1731 ind->stations_near.insert(st);
1732 st->AddIndustryToDeliver(ind, tile);
1733 return false;
1738 * Put an industry on the map.
1739 * @param i Just allocated poolitem, mostly empty.
1740 * @param tile North tile of the industry.
1741 * @param type Type of the industry.
1742 * @param layout Industrylayout to build.
1743 * @param layout_index Number of the industry layout.
1744 * @param t Nearest town.
1745 * @param founder Founder of the industry; OWNER_NONE in case of random construction.
1746 * @param initial_random_bits Random bits for the industry.
1748 static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, const IndustryTileLayout &layout, size_t layout_index, Town *t, Owner founder, uint16 initial_random_bits)
1750 const IndustrySpec *indspec = GetIndustrySpec(type);
1752 i->location = TileArea(tile, 1, 1);
1753 i->type = type;
1754 Industry::IncIndustryTypeCount(type);
1756 MemCpyT(i->produced_cargo, indspec->produced_cargo, lengthof(i->produced_cargo));
1757 MemCpyT(i->production_rate, indspec->production_rate, lengthof(i->production_rate));
1758 MemCpyT(i->accepts_cargo, indspec->accepts_cargo, lengthof(i->accepts_cargo));
1760 MemSetT(i->produced_cargo_waiting, 0, lengthof(i->produced_cargo_waiting));
1761 MemSetT(i->this_month_production, 0, lengthof(i->this_month_production));
1762 MemSetT(i->this_month_transported, 0, lengthof(i->this_month_transported));
1763 MemSetT(i->last_month_pct_transported, 0, lengthof(i->last_month_pct_transported));
1764 MemSetT(i->last_month_transported, 0, lengthof(i->last_month_transported));
1765 MemSetT(i->incoming_cargo_waiting, 0, lengthof(i->incoming_cargo_waiting));
1766 MemSetT(i->last_cargo_accepted_at, 0, lengthof(i->last_cargo_accepted_at));
1768 /* Randomize inital production if non-original economy is used and there are no production related callbacks. */
1769 if (!indspec->UsesOriginalEconomy()) {
1770 for (size_t ci = 0; ci < lengthof(i->production_rate); ci++) {
1771 i->production_rate[ci] = std::min((RandomRange(256) + 128) * i->production_rate[ci] >> 8, 255u);
1775 i->town = t;
1776 i->owner = OWNER_NONE;
1778 uint16 r = Random();
1779 i->random_colour = GB(r, 0, 4);
1780 i->counter = GB(r, 4, 12);
1781 i->random = initial_random_bits;
1782 i->was_cargo_delivered = false;
1783 i->last_prod_year = _cur_year;
1784 i->founder = founder;
1785 i->ctlflags = INDCTL_NONE;
1787 i->construction_date = _date;
1788 i->construction_type = (_game_mode == GM_EDITOR) ? ICT_SCENARIO_EDITOR :
1789 (_generating_world ? ICT_MAP_GENERATION : ICT_NORMAL_GAMEPLAY);
1791 /* Adding 1 here makes it conform to specs of var44 of varaction2 for industries
1792 * 0 = created prior of newindustries
1793 * else, chosen layout + 1 */
1794 i->selected_layout = (byte)(layout_index + 1);
1796 i->exclusive_supplier = INVALID_OWNER;
1797 i->exclusive_consumer = INVALID_OWNER;
1799 i->prod_level = PRODLEVEL_DEFAULT;
1801 /* Call callbacks after the regular fields got initialised. */
1803 if (HasBit(indspec->callback_mask, CBM_IND_PROD_CHANGE_BUILD)) {
1804 uint16 res = GetIndustryCallback(CBID_INDUSTRY_PROD_CHANGE_BUILD, 0, Random(), i, type, INVALID_TILE);
1805 if (res != CALLBACK_FAILED) {
1806 if (res < PRODLEVEL_MINIMUM || res > PRODLEVEL_MAXIMUM) {
1807 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_PROD_CHANGE_BUILD, res);
1808 } else {
1809 i->prod_level = res;
1810 i->RecomputeProductionMultipliers();
1815 if (_generating_world) {
1816 if (HasBit(indspec->callback_mask, CBM_IND_PRODUCTION_256_TICKS)) {
1817 IndustryProductionCallback(i, 1);
1818 for (size_t ci = 0; ci < lengthof(i->last_month_production); ci++) {
1819 i->last_month_production[ci] = i->produced_cargo_waiting[ci] * 8;
1820 i->produced_cargo_waiting[ci] = 0;
1824 for (size_t ci = 0; ci < lengthof(i->last_month_production); ci++) {
1825 i->last_month_production[ci] += i->production_rate[ci] * 8;
1829 if (HasBit(indspec->callback_mask, CBM_IND_DECIDE_COLOUR)) {
1830 uint16 res = GetIndustryCallback(CBID_INDUSTRY_DECIDE_COLOUR, 0, 0, i, type, INVALID_TILE);
1831 if (res != CALLBACK_FAILED) {
1832 if (GB(res, 4, 11) != 0) ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_DECIDE_COLOUR, res);
1833 i->random_colour = GB(res, 0, 4);
1837 if (HasBit(indspec->callback_mask, CBM_IND_INPUT_CARGO_TYPES)) {
1838 /* Clear all input cargo types */
1839 for (uint j = 0; j < lengthof(i->accepts_cargo); j++) i->accepts_cargo[j] = CT_INVALID;
1840 /* Query actual types */
1841 uint maxcargoes = (indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED) ? lengthof(i->accepts_cargo) : 3;
1842 for (uint j = 0; j < maxcargoes; j++) {
1843 uint16 res = GetIndustryCallback(CBID_INDUSTRY_INPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE);
1844 if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
1845 if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
1846 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_INPUT_CARGO_TYPES, res);
1847 break;
1849 CargoID cargo = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
1850 /* Industries without "unlimited" cargo types support depend on the specific order/slots of cargo types.
1851 * They need to be able to blank out specific slots without aborting the callback sequence,
1852 * and solve this by returning undefined cargo indexes. Skip these. */
1853 if (cargo == CT_INVALID && !(indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED)) continue;
1854 /* Verify valid cargo */
1855 if (std::find(indspec->accepts_cargo, endof(indspec->accepts_cargo), cargo) == endof(indspec->accepts_cargo)) {
1856 /* Cargo not in spec, error in NewGRF */
1857 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_INPUT_CARGO_TYPES, res);
1858 break;
1860 if (std::find(i->accepts_cargo, i->accepts_cargo + j, cargo) != i->accepts_cargo + j) {
1861 /* Duplicate cargo */
1862 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_INPUT_CARGO_TYPES, res);
1863 break;
1865 i->accepts_cargo[j] = cargo;
1869 if (HasBit(indspec->callback_mask, CBM_IND_OUTPUT_CARGO_TYPES)) {
1870 /* Clear all output cargo types */
1871 for (uint j = 0; j < lengthof(i->produced_cargo); j++) i->produced_cargo[j] = CT_INVALID;
1872 /* Query actual types */
1873 uint maxcargoes = (indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED) ? lengthof(i->produced_cargo) : 2;
1874 for (uint j = 0; j < maxcargoes; j++) {
1875 uint16 res = GetIndustryCallback(CBID_INDUSTRY_OUTPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE);
1876 if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
1877 if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
1878 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_OUTPUT_CARGO_TYPES, res);
1879 break;
1881 CargoID cargo = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
1882 /* Allow older GRFs to skip slots. */
1883 if (cargo == CT_INVALID && !(indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED)) continue;
1884 /* Verify valid cargo */
1885 if (std::find(indspec->produced_cargo, endof(indspec->produced_cargo), cargo) == endof(indspec->produced_cargo)) {
1886 /* Cargo not in spec, error in NewGRF */
1887 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_OUTPUT_CARGO_TYPES, res);
1888 break;
1890 if (std::find(i->produced_cargo, i->produced_cargo + j, cargo) != i->produced_cargo + j) {
1891 /* Duplicate cargo */
1892 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_OUTPUT_CARGO_TYPES, res);
1893 break;
1895 i->produced_cargo[j] = cargo;
1899 /* Plant the tiles */
1901 for (const IndustryTileLayoutTile &it : layout) {
1902 TileIndex cur_tile = tile + ToTileIndexDiff(it.ti);
1904 if (it.gfx != GFX_WATERTILE_SPECIALCHECK) {
1905 i->location.Add(cur_tile);
1907 WaterClass wc = (IsWaterTile(cur_tile) ? GetWaterClass(cur_tile) : WATER_CLASS_INVALID);
1909 Command<CMD_LANDSCAPE_CLEAR>::Do(DC_EXEC | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, cur_tile);
1911 MakeIndustry(cur_tile, i->index, it.gfx, Random(), wc);
1913 if (_generating_world) {
1914 SetIndustryConstructionCounter(cur_tile, 3);
1915 SetIndustryConstructionStage(cur_tile, 2);
1918 /* it->gfx is stored in the map. But the translated ID cur_gfx is the interesting one */
1919 IndustryGfx cur_gfx = GetTranslatedIndustryTileID(it.gfx);
1920 const IndustryTileSpec *its = GetIndustryTileSpec(cur_gfx);
1921 if (its->animation.status != ANIM_STATUS_NO_ANIMATION) AddAnimatedTile(cur_tile);
1925 if (GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_PLANT_ON_BUILT) {
1926 for (uint j = 0; j != 50; j++) PlantRandomFarmField(i);
1928 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, IDIWD_FORCE_REBUILD);
1930 if (!_generating_world) PopulateStationsNearby(i);
1934 * Helper function for Build/Fund an industry
1935 * @param tile tile where industry is built
1936 * @param type of industry to build
1937 * @param flags of operations to conduct
1938 * @param indspec pointer to industry specifications
1939 * @param layout_index the index of the itsepc to build/fund
1940 * @param random_var8f random seed (possibly) used by industries
1941 * @param random_initial_bits The random bits the industry is going to have after construction.
1942 * @param founder Founder of the industry
1943 * @param creation_type The circumstances the industry is created under.
1944 * @param[out] ip Pointer to store newly created industry.
1945 * @return Succeeded or failed command.
1947 * @post \c *ip contains the newly created industry if all checks are successful and the \a flags request actual creation, else it contains \c nullptr afterwards.
1949 static CommandCost CreateNewIndustryHelper(TileIndex tile, IndustryType type, DoCommandFlag flags, const IndustrySpec *indspec, size_t layout_index, uint32 random_var8f, uint16 random_initial_bits, Owner founder, IndustryAvailabilityCallType creation_type, Industry **ip)
1951 assert(layout_index < indspec->layouts.size());
1952 const IndustryTileLayout &layout = indspec->layouts[layout_index];
1954 *ip = nullptr;
1956 /* 1. Cheap: Built-in checks on industry level. */
1957 CommandCost ret = CheckIfFarEnoughFromConflictingIndustry(tile, type);
1958 if (ret.Failed()) return ret;
1960 Town *t = nullptr;
1961 ret = FindTownForIndustry(tile, type, &t);
1962 if (ret.Failed()) return ret;
1963 assert(t != nullptr);
1965 ret = CheckIfIndustryIsAllowed(tile, type, t);
1966 if (ret.Failed()) return ret;
1968 /* 2. Built-in checks on industry tiles. */
1969 std::vector<ClearedObjectArea> object_areas(_cleared_object_areas);
1970 ret = CheckIfIndustryTilesAreFree(tile, layout, type);
1971 _cleared_object_areas = object_areas;
1972 if (ret.Failed()) return ret;
1974 /* 3. NewGRF-defined checks on industry level. */
1975 if (HasBit(GetIndustrySpec(type)->callback_mask, CBM_IND_LOCATION)) {
1976 ret = CheckIfCallBackAllowsCreation(tile, type, layout_index, random_var8f, random_initial_bits, founder, creation_type);
1977 } else {
1978 ret = _check_new_industry_procs[indspec->check_proc](tile);
1980 if (ret.Failed()) return ret;
1982 /* 4. Expensive: NewGRF-defined checks on industry tiles. */
1983 bool custom_shape_check = false;
1984 ret = CheckIfIndustryTileSlopes(tile, layout, layout_index, type, random_initial_bits, founder, creation_type, &custom_shape_check);
1985 if (ret.Failed()) return ret;
1987 if (!custom_shape_check && _settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world &&
1988 !_ignore_restrictions && !CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER, layout, type)) {
1989 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1992 if (!Industry::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_INDUSTRIES);
1994 if (flags & DC_EXEC) {
1995 *ip = new Industry(tile);
1996 if (!custom_shape_check) CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER | DC_EXEC, layout, type);
1997 DoCreateNewIndustry(*ip, tile, type, layout, layout_index, t, founder, random_initial_bits);
2000 return CommandCost();
2004 * Build/Fund an industry
2005 * @param flags of operations to conduct
2006 * @param tile tile where industry is built
2007 * @param it industry type see build_industry.h and see industry.h
2008 * @param first_layout first layout to try
2009 * @param fund false = prospect, true = fund (only valid if current company is DEITY)
2010 * @param seed seed to use for desyncfree randomisations
2011 * @return the cost of this operation or an error
2013 CommandCost CmdBuildIndustry(DoCommandFlag flags, TileIndex tile, IndustryType it, uint32 first_layout, bool fund, uint32 seed)
2015 if (it >= NUM_INDUSTRYTYPES) return CMD_ERROR;
2017 const IndustrySpec *indspec = GetIndustrySpec(it);
2019 /* Check if the to-be built/founded industry is available for this climate. */
2020 if (!indspec->enabled || indspec->layouts.empty()) return CMD_ERROR;
2022 /* If the setting for raw-material industries is not on, you cannot build raw-material industries.
2023 * Raw material industries are industries that do not accept cargo (at least for now) */
2024 if (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 0 && indspec->IsRawIndustry()) {
2025 return CMD_ERROR;
2028 if (_game_mode != GM_EDITOR && GetIndustryProbabilityCallback(it, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, 1) == 0) {
2029 return CMD_ERROR;
2032 Randomizer randomizer;
2033 randomizer.SetSeed(seed);
2034 uint16 random_initial_bits = GB(seed, 0, 16);
2035 uint32 random_var8f = randomizer.Next();
2036 size_t num_layouts = indspec->layouts.size();
2037 CommandCost ret = CommandCost(STR_ERROR_SITE_UNSUITABLE);
2038 const bool deity_prospect = _current_company == OWNER_DEITY && !fund;
2040 Industry *ind = nullptr;
2041 if (deity_prospect || (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 2 && indspec->IsRawIndustry())) {
2042 if (flags & DC_EXEC) {
2043 /* Prospected industries are build as OWNER_TOWN to not e.g. be build on owned land of the founder */
2044 Backup<CompanyID> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
2045 /* Prospecting has a chance to fail, however we cannot guarantee that something can
2046 * be built on the map, so the chance gets lower when the map is fuller, but there
2047 * is nothing we can really do about that. */
2048 if (deity_prospect || Random() <= indspec->prospecting_chance) {
2049 for (int i = 0; i < 5000; i++) {
2050 /* We should not have more than one Random() in a function call
2051 * because parameter evaluation order is not guaranteed in the c++ standard
2053 tile = RandomTile();
2054 /* Start with a random layout */
2055 size_t layout = RandomRange((uint32)num_layouts);
2056 /* Check now each layout, starting with the random one */
2057 for (size_t j = 0; j < num_layouts; j++) {
2058 layout = (layout + 1) % num_layouts;
2059 ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, cur_company.GetOriginalValue(), _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_PROSPECTCREATION, &ind);
2060 if (ret.Succeeded()) break;
2062 if (ret.Succeeded()) break;
2065 cur_company.Restore();
2067 } else {
2068 size_t layout = first_layout;
2069 if (layout >= num_layouts) return CMD_ERROR;
2071 /* Check subsequently each layout, starting with the given layout in p1 */
2072 for (size_t i = 0; i < num_layouts; i++) {
2073 layout = (layout + 1) % num_layouts;
2074 ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, _current_company, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, &ind);
2075 if (ret.Succeeded()) break;
2078 /* If it still failed, there's no suitable layout to build here, return the error */
2079 if (ret.Failed()) return ret;
2082 if ((flags & DC_EXEC) && ind != nullptr && _game_mode != GM_EDITOR) {
2083 AdvertiseIndustryOpening(ind);
2086 return CommandCost(EXPENSES_OTHER, indspec->GetConstructionCost());
2090 * Change industry properties
2091 * @param flags Type of operation.
2092 * @param ind_id IndustryID
2093 * @param action IndustryAction to perform
2094 * @param ctlflags IndustryControlFlags (only used with set control flags)
2095 * @param company_id CompanyID to set or INVALID_OWNER (available to everyone) or
2096 * OWNER_NONE (neutral stations only) or OWNER_DEITY (no one)
2097 * (only used with set exclusive supplier / consumer)
2098 * @param text - Additional industry text (only used with set text action)
2099 * @return Empty cost or an error.
2101 CommandCost CmdIndustryCtrl(DoCommandFlag flags, IndustryID ind_id, IndustryAction action, IndustryControlFlags ctlflags, Owner company_id, const std::string &text)
2103 if (_current_company != OWNER_DEITY) return CMD_ERROR;
2105 Industry *ind = Industry::GetIfValid(ind_id);
2106 if (ind == nullptr) return CMD_ERROR;
2108 switch (action) {
2109 case IndustryAction::SetControlFlags: {
2110 if (flags & DC_EXEC) ind->ctlflags = ctlflags & INDCTL_MASK;
2112 break;
2115 case IndustryAction::SetExclusiveSupplier:
2116 case IndustryAction::SetExclusiveConsumer: {
2117 if (company_id != OWNER_NONE && company_id != INVALID_OWNER && company_id != OWNER_DEITY
2118 && !Company::IsValidID(company_id)) return CMD_ERROR;
2120 if (flags & DC_EXEC) {
2121 if (action == IndustryAction::SetExclusiveSupplier) {
2122 ind->exclusive_supplier = company_id;
2123 } else {
2124 ind->exclusive_consumer = company_id;
2128 break;
2131 case IndustryAction::SetText: {
2132 ind->text.clear();
2133 if (!text.empty()) ind->text = text;
2134 InvalidateWindowData(WC_INDUSTRY_VIEW, ind->index);
2135 break;
2138 default:
2139 return CMD_ERROR;
2142 return CommandCost();
2146 * Create a new industry of random layout.
2147 * @param tile The location to build the industry.
2148 * @param type The industry type to build.
2149 * @param creation_type The circumstances the industry is created under.
2150 * @return the created industry or nullptr if it failed.
2152 static Industry *CreateNewIndustry(TileIndex tile, IndustryType type, IndustryAvailabilityCallType creation_type)
2154 const IndustrySpec *indspec = GetIndustrySpec(type);
2156 uint32 seed = Random();
2157 uint32 seed2 = Random();
2158 Industry *i = nullptr;
2159 size_t layout_index = RandomRange((uint32)indspec->layouts.size());
2160 [[maybe_unused]] CommandCost ret = CreateNewIndustryHelper(tile, type, DC_EXEC, indspec, layout_index, seed, GB(seed2, 0, 16), OWNER_NONE, creation_type, &i);
2161 assert(i != nullptr || ret.Failed());
2162 return i;
2166 * Compute the appearance probability for an industry during map creation.
2167 * @param it Industry type to compute.
2168 * @param[out] force_at_least_one Returns whether at least one instance should be forced on map creation.
2169 * @return Relative probability for the industry to appear.
2171 static uint32 GetScaledIndustryGenerationProbability(IndustryType it, bool *force_at_least_one)
2173 const IndustrySpec *ind_spc = GetIndustrySpec(it);
2174 uint32 chance = ind_spc->appear_creation[_settings_game.game_creation.landscape];
2175 if (!ind_spc->enabled || ind_spc->layouts.empty() ||
2176 (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == ID_FUND_ONLY) ||
2177 (chance = GetIndustryProbabilityCallback(it, IACT_MAPGENERATION, chance)) == 0) {
2178 *force_at_least_one = false;
2179 return 0;
2180 } else {
2181 chance *= 16; // to increase precision
2182 /* We want industries appearing at coast to appear less often on bigger maps, as length of coast increases slower than map area.
2183 * For simplicity we scale in both cases, though scaling the probabilities of all industries has no effect. */
2184 chance = (ind_spc->check_proc == CHECK_REFINERY || ind_spc->check_proc == CHECK_OIL_RIG) ? ScaleByMapSize1D(chance) : ScaleByMapSize(chance);
2186 *force_at_least_one = (chance > 0) && !(ind_spc->behaviour & INDUSTRYBEH_NOBUILT_MAPCREATION) && (_game_mode != GM_EDITOR);
2187 return chance;
2192 * Compute the probability for constructing a new industry during game play.
2193 * @param it Industry type to compute.
2194 * @param[out] min_number Minimal number of industries that should exist at the map.
2195 * @return Relative probability for the industry to appear.
2197 static uint16 GetIndustryGamePlayProbability(IndustryType it, byte *min_number)
2199 if (_settings_game.difficulty.industry_density == ID_FUND_ONLY) {
2200 *min_number = 0;
2201 return 0;
2204 const IndustrySpec *ind_spc = GetIndustrySpec(it);
2205 byte chance = ind_spc->appear_ingame[_settings_game.game_creation.landscape];
2206 if (!ind_spc->enabled || ind_spc->layouts.empty() ||
2207 ((ind_spc->behaviour & INDUSTRYBEH_BEFORE_1950) && _cur_year > 1950) ||
2208 ((ind_spc->behaviour & INDUSTRYBEH_AFTER_1960) && _cur_year < 1960) ||
2209 (chance = GetIndustryProbabilityCallback(it, IACT_RANDOMCREATION, chance)) == 0) {
2210 *min_number = 0;
2211 return 0;
2213 *min_number = (ind_spc->behaviour & INDUSTRYBEH_CANCLOSE_LASTINSTANCE) ? 1 : 0;
2214 return chance;
2218 * Get wanted number of industries on the map.
2219 * @return Wanted number of industries at the map.
2221 static uint GetNumberOfIndustries()
2223 /* Number of industries on a 256x256 map. */
2224 static const uint16 numof_industry_table[] = {
2225 0, // none
2226 0, // minimal
2227 10, // very low
2228 25, // low
2229 55, // normal
2230 80, // high
2233 assert(lengthof(numof_industry_table) == ID_END);
2234 uint difficulty = (_game_mode != GM_EDITOR) ? _settings_game.difficulty.industry_density : (uint)ID_VERY_LOW;
2235 return std::min<uint>(IndustryPool::MAX_SIZE, ScaleByMapSize(numof_industry_table[difficulty]));
2239 * Try to place the industry in the game.
2240 * Since there is no feedback why placement fails, there is no other option
2241 * than to try a few times before concluding it does not work.
2242 * @param type Industry type of the desired industry.
2243 * @param try_hard Try very hard to find a place. (Used to place at least one industry per type.)
2244 * @return Pointer to created industry, or \c nullptr if creation failed.
2246 static Industry *PlaceIndustry(IndustryType type, IndustryAvailabilityCallType creation_type, bool try_hard)
2248 uint tries = try_hard ? 10000u : 2000u;
2249 for (; tries > 0; tries--) {
2250 Industry *ind = CreateNewIndustry(RandomTile(), type, creation_type);
2251 if (ind != nullptr) return ind;
2253 return nullptr;
2257 * Try to build a industry on the map.
2258 * @param type IndustryType of the desired industry
2259 * @param try_hard Try very hard to find a place. (Used to place at least one industry per type)
2261 static void PlaceInitialIndustry(IndustryType type, bool try_hard)
2263 Backup<CompanyID> cur_company(_current_company, OWNER_NONE, FILE_LINE);
2265 IncreaseGeneratingWorldProgress(GWP_INDUSTRY);
2266 PlaceIndustry(type, IACT_MAPGENERATION, try_hard);
2268 cur_company.Restore();
2272 * Get total number of industries existing in the game.
2273 * @return Number of industries currently in the game.
2275 static uint GetCurrentTotalNumberOfIndustries()
2277 int total = 0;
2278 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) total += Industry::GetIndustryTypeCount(it);
2279 return total;
2283 /** Reset the entry. */
2284 void IndustryTypeBuildData::Reset()
2286 this->probability = 0;
2287 this->min_number = 0;
2288 this->target_count = 0;
2289 this->max_wait = 1;
2290 this->wait_count = 0;
2293 /** Completely reset the industry build data. */
2294 void IndustryBuildData::Reset()
2296 this->wanted_inds = GetCurrentTotalNumberOfIndustries() << 16;
2298 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2299 this->builddata[it].Reset();
2303 /** Monthly update of industry build data. */
2304 void IndustryBuildData::MonthlyLoop()
2306 static const int NEWINDS_PER_MONTH = 0x38000 / (10 * 12); // lower 16 bits is a float fraction, 3.5 industries per decade, divided by 10 * 12 months.
2307 if (_settings_game.difficulty.industry_density == ID_FUND_ONLY) return; // 'no industries' setting.
2309 /* To prevent running out of unused industries for the player to connect,
2310 * add a fraction of new industries each month, but only if the manager can keep up. */
2311 uint max_behind = 1 + std::min(99u, ScaleByMapSize(3)); // At most 2 industries for small maps, and 100 at the biggest map (about 6 months industry build attempts).
2312 if (GetCurrentTotalNumberOfIndustries() + max_behind >= (this->wanted_inds >> 16)) {
2313 this->wanted_inds += ScaleByMapSize(NEWINDS_PER_MONTH);
2318 * This function will create random industries during game creation.
2319 * It will scale the amount of industries by mapsize and difficulty level.
2321 void GenerateIndustries()
2323 if (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == ID_FUND_ONLY) return; // No industries in the game.
2325 uint32 industry_probs[NUM_INDUSTRYTYPES];
2326 bool force_at_least_one[NUM_INDUSTRYTYPES];
2327 uint32 total_prob = 0;
2328 uint num_forced = 0;
2330 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2331 industry_probs[it] = GetScaledIndustryGenerationProbability(it, force_at_least_one + it);
2332 total_prob += industry_probs[it];
2333 if (force_at_least_one[it]) num_forced++;
2336 uint total_amount = GetNumberOfIndustries();
2337 if (total_prob == 0 || total_amount < num_forced) {
2338 /* Only place the forced ones */
2339 total_amount = num_forced;
2342 SetGeneratingWorldProgress(GWP_INDUSTRY, total_amount);
2344 /* Try to build one industry per type independent of any probabilities */
2345 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2346 if (force_at_least_one[it]) {
2347 assert(total_amount > 0);
2348 total_amount--;
2349 PlaceInitialIndustry(it, true);
2353 /* Add the remaining industries according to their probabilities */
2354 for (uint i = 0; i < total_amount; i++) {
2355 uint32 r = RandomRange(total_prob);
2356 IndustryType it = 0;
2357 while (r >= industry_probs[it]) {
2358 r -= industry_probs[it];
2359 it++;
2360 assert(it < NUM_INDUSTRYTYPES);
2362 assert(industry_probs[it] > 0);
2363 PlaceInitialIndustry(it, false);
2365 _industry_builder.Reset();
2369 * Monthly update of industry statistics.
2370 * @param i Industry to update.
2372 static void UpdateIndustryStatistics(Industry *i)
2374 for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
2375 if (i->produced_cargo[j] != CT_INVALID) {
2376 byte pct = 0;
2377 if (i->this_month_production[j] != 0) {
2378 i->last_prod_year = _cur_year;
2379 pct = std::min(i->this_month_transported[j] * 256 / i->this_month_production[j], 255);
2381 i->last_month_pct_transported[j] = pct;
2383 i->last_month_production[j] = i->this_month_production[j];
2384 i->this_month_production[j] = 0;
2386 i->last_month_transported[j] = i->this_month_transported[j];
2387 i->this_month_transported[j] = 0;
2393 * Recompute #production_rate for current #prod_level.
2394 * This function is only valid when not using smooth economy.
2396 void Industry::RecomputeProductionMultipliers()
2398 const IndustrySpec *indspec = GetIndustrySpec(this->type);
2399 assert(indspec->UsesOriginalEconomy());
2401 /* Rates are rounded up, so e.g. oilrig always produces some passengers */
2402 for (size_t i = 0; i < lengthof(this->production_rate); i++) {
2403 this->production_rate[i] = std::min(CeilDiv(indspec->production_rate[i] * this->prod_level, PRODLEVEL_DEFAULT), 0xFFu);
2407 void Industry::FillCachedName() const
2409 char buf[256];
2410 int64 args_array[] = { this->index };
2411 StringParameters tmp_params(args_array);
2412 char *end = GetStringWithArgs(buf, STR_INDUSTRY_NAME, &tmp_params, lastof(buf));
2413 this->cached_name.assign(buf, end);
2416 void ClearAllIndustryCachedNames()
2418 for (Industry *ind : Industry::Iterate()) {
2419 ind->cached_name.clear();
2424 * Set the #probability and #min_number fields for the industry type \a it for a running game.
2425 * @param it Industry type.
2426 * @return At least one of the fields has changed value.
2428 bool IndustryTypeBuildData::GetIndustryTypeData(IndustryType it)
2430 byte min_number;
2431 uint32 probability = GetIndustryGamePlayProbability(it, &min_number);
2432 bool changed = min_number != this->min_number || probability != this->probability;
2433 this->min_number = min_number;
2434 this->probability = probability;
2435 return changed;
2438 /** Decide how many industries of each type are needed. */
2439 void IndustryBuildData::SetupTargetCount()
2441 bool changed = false;
2442 uint num_planned = 0; // Number of industries planned in the industry build data.
2443 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2444 changed |= this->builddata[it].GetIndustryTypeData(it);
2445 num_planned += this->builddata[it].target_count;
2447 uint total_amount = this->wanted_inds >> 16; // Desired total number of industries.
2448 changed |= num_planned != total_amount;
2449 if (!changed) return; // All industries are still the same, no need to re-randomize.
2451 /* Initialize the target counts. */
2452 uint force_build = 0; // Number of industries that should always be available.
2453 uint32 total_prob = 0; // Sum of probabilities.
2454 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2455 IndustryTypeBuildData *ibd = this->builddata + it;
2456 force_build += ibd->min_number;
2457 ibd->target_count = ibd->min_number;
2458 total_prob += ibd->probability;
2461 if (total_prob == 0) return; // No buildable industries.
2463 /* Subtract forced industries from the number of industries available for construction. */
2464 total_amount = (total_amount <= force_build) ? 0 : total_amount - force_build;
2466 /* Assign number of industries that should be aimed for, by using the probability as a weight. */
2467 while (total_amount > 0) {
2468 uint32 r = RandomRange(total_prob);
2469 IndustryType it = 0;
2470 while (r >= this->builddata[it].probability) {
2471 r -= this->builddata[it].probability;
2472 it++;
2473 assert(it < NUM_INDUSTRYTYPES);
2475 assert(this->builddata[it].probability > 0);
2476 this->builddata[it].target_count++;
2477 total_amount--;
2482 * Try to create a random industry, during gameplay
2484 void IndustryBuildData::TryBuildNewIndustry()
2486 this->SetupTargetCount();
2488 int missing = 0; // Number of industries that need to be build.
2489 uint count = 0; // Number of industry types eligible for build.
2490 uint32 total_prob = 0; // Sum of probabilities.
2491 IndustryType forced_build = NUM_INDUSTRYTYPES; // Industry type that should be forcibly build.
2492 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2493 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
2494 missing += difference;
2495 if (this->builddata[it].wait_count > 0) continue; // This type may not be built now.
2496 if (difference > 0) {
2497 if (Industry::GetIndustryTypeCount(it) == 0 && this->builddata[it].min_number > 0) {
2498 /* An industry that should exist at least once, is not available. Force it, trying the most needed one first. */
2499 if (forced_build == NUM_INDUSTRYTYPES ||
2500 difference > this->builddata[forced_build].target_count - Industry::GetIndustryTypeCount(forced_build)) {
2501 forced_build = it;
2504 total_prob += difference;
2505 count++;
2509 if (EconomyIsInRecession() || (forced_build == NUM_INDUSTRYTYPES && (missing <= 0 || total_prob == 0))) count = 0; // Skip creation of an industry.
2511 if (count >= 1) {
2512 /* If not forced, pick a weighted random industry to build.
2513 * For the case that count == 1, there is no need to draw a random number. */
2514 IndustryType it;
2515 if (forced_build != NUM_INDUSTRYTYPES) {
2516 it = forced_build;
2517 } else {
2518 /* Non-forced, select an industry type to build (weighted random). */
2519 uint32 r = 0; // Initialized to silence the compiler.
2520 if (count > 1) r = RandomRange(total_prob);
2521 for (it = 0; it < NUM_INDUSTRYTYPES; it++) {
2522 if (this->builddata[it].wait_count > 0) continue; // Type may not be built now.
2523 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
2524 if (difference <= 0) continue; // Too many of this kind.
2525 if (count == 1) break;
2526 if (r < (uint)difference) break;
2527 r -= difference;
2529 assert(it < NUM_INDUSTRYTYPES && this->builddata[it].target_count > Industry::GetIndustryTypeCount(it));
2532 /* Try to create the industry. */
2533 const Industry *ind = PlaceIndustry(it, IACT_RANDOMCREATION, false);
2534 if (ind == nullptr) {
2535 this->builddata[it].wait_count = this->builddata[it].max_wait + 1; // Compensate for decrementing below.
2536 this->builddata[it].max_wait = std::min(1000, this->builddata[it].max_wait + 2);
2537 } else {
2538 AdvertiseIndustryOpening(ind);
2539 this->builddata[it].max_wait = std::max(this->builddata[it].max_wait / 2, 1); // Reduce waiting time of the industry type.
2543 /* Decrement wait counters. */
2544 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2545 if (this->builddata[it].wait_count > 0) this->builddata[it].wait_count--;
2550 * Protects an industry from closure if the appropriate flags and conditions are met
2551 * INDUSTRYBEH_CANCLOSE_LASTINSTANCE must be set (which, by default, it is not) and the
2552 * count of industries of this type must one (or lower) in order to be protected
2553 * against closure.
2554 * @param type IndustryType been queried
2555 * @result true if protection is on, false otherwise (except for oil wells)
2557 static bool CheckIndustryCloseDownProtection(IndustryType type)
2559 const IndustrySpec *indspec = GetIndustrySpec(type);
2561 /* oil wells (or the industries with that flag set) are always allowed to closedown */
2562 if ((indspec->behaviour & INDUSTRYBEH_DONT_INCR_PROD) && _settings_game.game_creation.landscape == LT_TEMPERATE) return false;
2563 return (indspec->behaviour & INDUSTRYBEH_CANCLOSE_LASTINSTANCE) == 0 && Industry::GetIndustryTypeCount(type) <= 1;
2567 * Can given cargo type be accepted or produced by the industry?
2568 * @param cargo: Cargo type
2569 * @param ind: Industry
2570 * @param *c_accepts: Pointer to boolean for acceptance of cargo
2571 * @param *c_produces: Pointer to boolean for production of cargo
2572 * @return: \c *c_accepts is set when industry accepts the cargo type,
2573 * \c *c_produces is set when the industry produces the cargo type
2575 static void CanCargoServiceIndustry(CargoID cargo, Industry *ind, bool *c_accepts, bool *c_produces)
2577 if (cargo == CT_INVALID) return;
2579 /* Check for acceptance of cargo */
2580 for (byte j = 0; j < lengthof(ind->accepts_cargo); j++) {
2581 if (cargo == ind->accepts_cargo[j] && !IndustryTemporarilyRefusesCargo(ind, cargo)) {
2582 *c_accepts = true;
2583 break;
2587 /* Check for produced cargo */
2588 for (byte j = 0; j < lengthof(ind->produced_cargo); j++) {
2589 if (cargo == ind->produced_cargo[j]) {
2590 *c_produces = true;
2591 break;
2597 * Compute who can service the industry.
2599 * Here, 'can service' means that they have trains and stations close enough
2600 * to the industry with the right cargo type and the right orders (ie has the
2601 * technical means).
2603 * @param ind: Industry being investigated.
2605 * @return: 0 if nobody can service the industry, 2 if the local company can
2606 * service the industry, and 1 otherwise (only competitors can service the
2607 * industry)
2609 static int WhoCanServiceIndustry(Industry *ind)
2611 if (ind->stations_near.size() == 0) return 0; // No stations found at all => nobody services
2613 int result = 0;
2614 for (const Vehicle *v : Vehicle::Iterate()) {
2615 /* Is it worthwhile to try this vehicle? */
2616 if (v->owner != _local_company && result != 0) continue;
2618 /* Check whether it accepts the right kind of cargo */
2619 bool c_accepts = false;
2620 bool c_produces = false;
2621 if (v->type == VEH_TRAIN && v->IsFrontEngine()) {
2622 for (const Vehicle *u = v; u != nullptr; u = u->Next()) {
2623 CanCargoServiceIndustry(u->cargo_type, ind, &c_accepts, &c_produces);
2625 } else if (v->type == VEH_ROAD || v->type == VEH_SHIP || v->type == VEH_AIRCRAFT) {
2626 CanCargoServiceIndustry(v->cargo_type, ind, &c_accepts, &c_produces);
2627 } else {
2628 continue;
2630 if (!c_accepts && !c_produces) continue; // Wrong cargo
2632 /* Check orders of the vehicle.
2633 * We cannot check the first of shared orders only, since the first vehicle in such a chain
2634 * may have a different cargo type.
2636 for (const Order *o : v->Orders()) {
2637 if (o->IsType(OT_GOTO_STATION) && !(o->GetUnloadType() & OUFB_TRANSFER)) {
2638 /* Vehicle visits a station to load or unload */
2639 Station *st = Station::Get(o->GetDestination());
2640 assert(st != nullptr);
2642 /* Same cargo produced by industry is dropped here => not serviced by vehicle v */
2643 if ((o->GetUnloadType() & OUFB_UNLOAD) && !c_accepts) break;
2645 if (ind->stations_near.find(st) != ind->stations_near.end()) {
2646 if (v->owner == _local_company) return 2; // Company services industry
2647 result = 1; // Competitor services industry
2652 return result;
2656 * Report news that industry production has changed significantly
2658 * @param ind: Industry with changed production
2659 * @param type: Cargo type that has changed
2660 * @param percent: Percentage of change (>0 means increase, <0 means decrease)
2662 static void ReportNewsProductionChangeIndustry(Industry *ind, CargoID type, int percent)
2664 NewsType nt;
2666 switch (WhoCanServiceIndustry(ind)) {
2667 case 0: nt = NT_INDUSTRY_NOBODY; break;
2668 case 1: nt = NT_INDUSTRY_OTHER; break;
2669 case 2: nt = NT_INDUSTRY_COMPANY; break;
2670 default: NOT_REACHED();
2672 SetDParam(2, abs(percent));
2673 SetDParam(0, CargoSpec::Get(type)->name);
2674 SetDParam(1, ind->index);
2675 AddIndustryNewsItem(
2676 percent >= 0 ? STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH : STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH,
2678 ind->index
2682 static const uint PERCENT_TRANSPORTED_60 = 153;
2683 static const uint PERCENT_TRANSPORTED_80 = 204;
2686 * Change industry production or do closure
2687 * @param i Industry for which changes are performed
2688 * @param monthly true if it's the monthly call, false if it's the random call
2690 static void ChangeIndustryProduction(Industry *i, bool monthly)
2692 StringID str = STR_NULL;
2693 bool closeit = false;
2694 const IndustrySpec *indspec = GetIndustrySpec(i->type);
2695 bool standard = false;
2696 bool suppress_message = false;
2697 bool recalculate_multipliers = false; ///< reinitialize production_rate to match prod_level
2698 /* use original economy for industries using production related callbacks */
2699 bool original_economy = indspec->UsesOriginalEconomy();
2700 byte div = 0;
2701 byte mul = 0;
2702 int8 increment = 0;
2704 bool callback_enabled = HasBit(indspec->callback_mask, monthly ? CBM_IND_MONTHLYPROD_CHANGE : CBM_IND_PRODUCTION_CHANGE);
2705 if (callback_enabled) {
2706 uint16 res = GetIndustryCallback(monthly ? CBID_INDUSTRY_MONTHLYPROD_CHANGE : CBID_INDUSTRY_PRODUCTION_CHANGE, 0, Random(), i, i->type, i->location.tile);
2707 if (res != CALLBACK_FAILED) { // failed callback means "do nothing"
2708 suppress_message = HasBit(res, 7);
2709 /* Get the custom message if any */
2710 if (HasBit(res, 8)) str = MapGRFStringID(indspec->grf_prop.grffile->grfid, GB(GetRegister(0x100), 0, 16));
2711 res = GB(res, 0, 4);
2712 switch (res) {
2713 default: NOT_REACHED();
2714 case 0x0: break; // Do nothing, but show the custom message if any
2715 case 0x1: div = 1; break; // Halve industry production. If production reaches the quarter of the default, the industry is closed instead.
2716 case 0x2: mul = 1; break; // Double industry production if it hasn't reached eight times of the original yet.
2717 case 0x3: closeit = true; break; // The industry announces imminent closure, and is physically removed from the map next month.
2718 case 0x4: standard = true; break; // Do the standard random production change as if this industry was a primary one.
2719 case 0x5: case 0x6: case 0x7: // Divide production by 4, 8, 16
2720 case 0x8: div = res - 0x3; break; // Divide production by 32
2721 case 0x9: case 0xA: case 0xB: // Multiply production by 4, 8, 16
2722 case 0xC: mul = res - 0x7; break; // Multiply production by 32
2723 case 0xD: // decrement production
2724 case 0xE: // increment production
2725 increment = res == 0x0D ? -1 : 1;
2726 break;
2727 case 0xF: // Set production to third byte of register 0x100
2728 i->prod_level = Clamp(GB(GetRegister(0x100), 16, 8), PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
2729 recalculate_multipliers = true;
2730 break;
2733 } else {
2734 if (monthly == original_economy) return;
2735 if (!original_economy && _settings_game.economy.type == ET_FROZEN) return;
2736 if (indspec->life_type == INDUSTRYLIFE_BLACK_HOLE) return;
2739 if (standard || (!callback_enabled && (indspec->life_type & (INDUSTRYLIFE_ORGANIC | INDUSTRYLIFE_EXTRACTIVE)) != 0)) {
2740 /* decrease or increase */
2741 bool only_decrease = (indspec->behaviour & INDUSTRYBEH_DONT_INCR_PROD) && _settings_game.game_creation.landscape == LT_TEMPERATE;
2743 if (original_economy) {
2744 if (only_decrease || Chance16(1, 3)) {
2745 /* If more than 60% transported, 66% chance of increase, else 33% chance of increase */
2746 if (!only_decrease && (i->last_month_pct_transported[0] > PERCENT_TRANSPORTED_60) != Chance16(1, 3)) {
2747 mul = 1; // Increase production
2748 } else {
2749 div = 1; // Decrease production
2752 } else if (_settings_game.economy.type == ET_SMOOTH) {
2753 closeit = !(i->ctlflags & (INDCTL_NO_CLOSURE | INDCTL_NO_PRODUCTION_DECREASE));
2754 for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
2755 if (i->produced_cargo[j] == CT_INVALID) continue;
2756 uint32 r = Random();
2757 int old_prod, new_prod, percent;
2758 /* If over 60% is transported, mult is 1, else mult is -1. */
2759 int mult = (i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_60) ? 1 : -1;
2761 new_prod = old_prod = i->production_rate[j];
2763 /* For industries with only_decrease flags (temperate terrain Oil Wells),
2764 * the multiplier will always be -1 so they will only decrease. */
2765 if (only_decrease) {
2766 mult = -1;
2767 /* For normal industries, if over 60% is transported, 33% chance for decrease.
2768 * Bonus for very high station ratings (over 80%): 16% chance for decrease. */
2769 } else if (Chance16I(1, ((i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_80) ? 6 : 3), r)) {
2770 mult *= -1;
2773 /* 4.5% chance for 3-23% (or 1 unit for very low productions) production change,
2774 * determined by mult value. If mult = 1 prod. increases, else (-1) it decreases. */
2775 if (Chance16I(1, 22, r >> 16)) {
2776 new_prod += mult * (std::max(((RandomRange(50) + 10) * old_prod) >> 8, 1U));
2779 /* Prevent production to overflow or Oil Rig passengers to be over-"produced" */
2780 new_prod = Clamp(new_prod, 1, 255);
2781 if (i->produced_cargo[j] == CT_PASSENGERS && !(indspec->behaviour & INDUSTRYBEH_NO_PAX_PROD_CLAMP)) {
2782 new_prod = Clamp(new_prod, 0, 16);
2785 /* If override flags are set, prevent actually changing production if any was decided on */
2786 if ((i->ctlflags & INDCTL_NO_PRODUCTION_DECREASE) && new_prod < old_prod) continue;
2787 if ((i->ctlflags & INDCTL_NO_PRODUCTION_INCREASE) && new_prod > old_prod) continue;
2789 /* Do not stop closing the industry when it has the lowest possible production rate */
2790 if (new_prod == old_prod && old_prod > 1) {
2791 closeit = false;
2792 continue;
2795 percent = (old_prod == 0) ? 100 : (new_prod * 100 / old_prod - 100);
2796 i->production_rate[j] = new_prod;
2798 /* Close the industry when it has the lowest possible production rate */
2799 if (new_prod > 1) closeit = false;
2801 if (abs(percent) >= 10) {
2802 ReportNewsProductionChangeIndustry(i, i->produced_cargo[j], percent);
2808 /* If override flags are set, prevent actually changing production if any was decided on */
2809 if ((i->ctlflags & INDCTL_NO_PRODUCTION_DECREASE) && (div > 0 || increment < 0)) return;
2810 if ((i->ctlflags & INDCTL_NO_PRODUCTION_INCREASE) && (mul > 0 || increment > 0)) return;
2812 if (!callback_enabled && (indspec->life_type & INDUSTRYLIFE_PROCESSING)) {
2813 if ( (byte)(_cur_year - i->last_prod_year) >= 5 && Chance16(1, original_economy ? 2 : 180)) {
2814 closeit = true;
2818 /* Increase if needed */
2819 while (mul-- != 0 && i->prod_level < PRODLEVEL_MAXIMUM) {
2820 i->prod_level = std::min<int>(i->prod_level * 2, PRODLEVEL_MAXIMUM);
2821 recalculate_multipliers = true;
2822 if (str == STR_NULL) str = indspec->production_up_text;
2825 /* Decrease if needed */
2826 while (div-- != 0 && !closeit) {
2827 if (i->prod_level == PRODLEVEL_MINIMUM) {
2828 closeit = true;
2829 break;
2830 } else {
2831 i->prod_level = std::max<int>(i->prod_level / 2, PRODLEVEL_MINIMUM);
2832 recalculate_multipliers = true;
2833 if (str == STR_NULL) str = indspec->production_down_text;
2837 /* Increase or Decreasing the production level if needed */
2838 if (increment != 0) {
2839 if (increment < 0 && i->prod_level == PRODLEVEL_MINIMUM) {
2840 closeit = true;
2841 } else {
2842 i->prod_level = ClampU(i->prod_level + increment, PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
2843 recalculate_multipliers = true;
2847 /* Recalculate production_rate
2848 * For non-smooth economy these should always be synchronized with prod_level */
2849 if (recalculate_multipliers) i->RecomputeProductionMultipliers();
2851 /* Close if needed and allowed */
2852 if (closeit && !CheckIndustryCloseDownProtection(i->type) && !(i->ctlflags & INDCTL_NO_CLOSURE)) {
2853 i->prod_level = PRODLEVEL_CLOSURE;
2854 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
2855 str = indspec->closure_text;
2858 if (!suppress_message && str != STR_NULL) {
2859 NewsType nt;
2860 /* Compute news category */
2861 if (closeit) {
2862 nt = NT_INDUSTRY_CLOSE;
2863 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index));
2864 Game::NewEvent(new ScriptEventIndustryClose(i->index));
2865 } else {
2866 switch (WhoCanServiceIndustry(i)) {
2867 case 0: nt = NT_INDUSTRY_NOBODY; break;
2868 case 1: nt = NT_INDUSTRY_OTHER; break;
2869 case 2: nt = NT_INDUSTRY_COMPANY; break;
2870 default: NOT_REACHED();
2873 /* Set parameters of news string */
2874 if (str > STR_LAST_STRINGID) {
2875 SetDParam(0, STR_TOWN_NAME);
2876 SetDParam(1, i->town->index);
2877 SetDParam(2, indspec->name);
2878 } else if (closeit) {
2879 SetDParam(0, STR_FORMAT_INDUSTRY_NAME);
2880 SetDParam(1, i->town->index);
2881 SetDParam(2, indspec->name);
2882 } else {
2883 SetDParam(0, i->index);
2885 /* and report the news to the user */
2886 if (closeit) {
2887 AddTileNewsItem(str, nt, i->location.tile + TileDiffXY(1, 1));
2888 } else {
2889 AddIndustryNewsItem(str, nt, i->index);
2895 * Daily handler for the industry changes
2896 * Taking the original map size of 256*256, the number of random changes was always of just one unit.
2897 * But it cannot be the same on smaller or bigger maps. That number has to be scaled up or down.
2898 * For small maps, it implies that less than one change per month is required, while on bigger maps,
2899 * it would be way more. The daily loop handles those changes.
2901 void IndustryDailyLoop()
2903 _economy.industry_daily_change_counter += _economy.industry_daily_increment;
2905 /* Bits 16-31 of industry_construction_counter contain the number of industries to change/create today,
2906 * the lower 16 bit are a fractional part that might accumulate over several days until it
2907 * is sufficient for an industry. */
2908 uint16 change_loop = _economy.industry_daily_change_counter >> 16;
2910 /* Reset the active part of the counter, just keeping the "fractional part" */
2911 _economy.industry_daily_change_counter &= 0xFFFF;
2913 if (change_loop == 0) {
2914 return; // Nothing to do? get out
2917 Backup<CompanyID> cur_company(_current_company, OWNER_NONE, FILE_LINE);
2919 /* perform the required industry changes for the day */
2921 uint perc = 3; // Between 3% and 9% chance of creating a new industry.
2922 if ((_industry_builder.wanted_inds >> 16) > GetCurrentTotalNumberOfIndustries()) {
2923 perc = std::min(9u, perc + (_industry_builder.wanted_inds >> 16) - GetCurrentTotalNumberOfIndustries());
2925 for (uint16 j = 0; j < change_loop; j++) {
2926 if (Chance16(perc, 100)) {
2927 _industry_builder.TryBuildNewIndustry();
2928 } else {
2929 Industry *i = Industry::GetRandom();
2930 if (i != nullptr) {
2931 ChangeIndustryProduction(i, false);
2932 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
2937 cur_company.Restore();
2939 /* production-change */
2940 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, IDIWD_PRODUCTION_CHANGE);
2943 void IndustryMonthlyLoop()
2945 Backup<CompanyID> cur_company(_current_company, OWNER_NONE, FILE_LINE);
2947 _industry_builder.MonthlyLoop();
2949 for (Industry *i : Industry::Iterate()) {
2950 UpdateIndustryStatistics(i);
2951 if (i->prod_level == PRODLEVEL_CLOSURE) {
2952 delete i;
2953 } else {
2954 ChangeIndustryProduction(i, true);
2955 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
2959 cur_company.Restore();
2961 /* production-change */
2962 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, IDIWD_PRODUCTION_CHANGE);
2966 void InitializeIndustries()
2968 Industry::ResetIndustryCounts();
2969 _industry_sound_tile = 0;
2971 _industry_builder.Reset();
2974 /** Verify whether the generated industries are complete, and warn the user if not. */
2975 void CheckIndustries()
2977 int count = 0;
2978 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2979 if (Industry::GetIndustryTypeCount(it) > 0) continue; // Types of existing industries can be skipped.
2981 bool force_at_least_one;
2982 uint32 chance = GetScaledIndustryGenerationProbability(it, &force_at_least_one);
2983 if (chance == 0 || !force_at_least_one) continue; // Types that are not available can be skipped.
2985 const IndustrySpec *is = GetIndustrySpec(it);
2986 SetDParam(0, is->name);
2987 ShowErrorMessage(STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES, STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION, WL_WARNING);
2989 count++;
2990 if (count >= 3) break; // Don't swamp the user with errors.
2995 * Is an industry with the spec a raw industry?
2996 * @return true if it should be handled as a raw industry
2998 bool IndustrySpec::IsRawIndustry() const
3000 return (this->life_type & (INDUSTRYLIFE_EXTRACTIVE | INDUSTRYLIFE_ORGANIC)) != 0;
3004 * Is an industry with the spec a processing industry?
3005 * @return true if it should be handled as a processing industry
3007 bool IndustrySpec::IsProcessingIndustry() const
3009 /* Lumber mills are neither raw nor processing */
3010 return (this->life_type & INDUSTRYLIFE_PROCESSING) != 0 &&
3011 (this->behaviour & INDUSTRYBEH_CUT_TREES) == 0;
3015 * Get the cost for constructing this industry
3016 * @return the cost (inflation corrected etc)
3018 Money IndustrySpec::GetConstructionCost() const
3020 /* Building raw industries like secondary uses different price base */
3021 return (_price[(_settings_game.construction.raw_industry_construction == 1 && this->IsRawIndustry()) ?
3022 PR_BUILD_INDUSTRY_RAW : PR_BUILD_INDUSTRY] * this->cost_multiplier) >> 8;
3026 * Get the cost for removing this industry
3027 * Take note that the cost will always be zero for non-grf industries.
3028 * Only if the grf author did specified a cost will it be applicable.
3029 * @return the cost (inflation corrected etc)
3031 Money IndustrySpec::GetRemovalCost() const
3033 return (_price[PR_CLEAR_INDUSTRY] * this->removal_cost_multiplier) >> 8;
3037 * Determines whether this industrytype uses standard/newgrf production changes.
3038 * @return true if original economy is used.
3040 bool IndustrySpec::UsesOriginalEconomy() const
3042 return _settings_game.economy.type == ET_ORIGINAL ||
3043 HasBit(this->callback_mask, CBM_IND_PRODUCTION_256_TICKS) || HasBit(this->callback_mask, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || // production callbacks
3044 HasBit(this->callback_mask, CBM_IND_MONTHLYPROD_CHANGE) || HasBit(this->callback_mask, CBM_IND_PRODUCTION_CHANGE) || HasBit(this->callback_mask, CBM_IND_PROD_CHANGE_BUILD); // production change callbacks
3047 IndustrySpec::~IndustrySpec()
3049 if (HasBit(this->cleanup_flag, CLEAN_RANDOMSOUNDS)) {
3050 free(this->random_sounds);
3054 static CommandCost TerraformTile_Industry(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
3056 if (AutoslopeEnabled()) {
3057 /* We imitate here TTDP's behaviour:
3058 * - Both new and old slope must not be steep.
3059 * - TileMaxZ must not be changed.
3060 * - Allow autoslope by default.
3061 * - Disallow autoslope if callback succeeds and returns non-zero.
3063 Slope tileh_old = GetTileSlope(tile);
3064 /* TileMaxZ must not be changed. Slopes must not be steep. */
3065 if (!IsSteepSlope(tileh_old) && !IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) {
3066 const IndustryGfx gfx = GetIndustryGfx(tile);
3067 const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
3069 /* Call callback 3C 'disable autosloping for industry tiles'. */
3070 if (HasBit(itspec->callback_mask, CBM_INDT_AUTOSLOPE)) {
3071 /* If the callback fails, allow autoslope. */
3072 uint16 res = GetIndustryTileCallback(CBID_INDTILE_AUTOSLOPE, 0, 0, gfx, Industry::GetByTile(tile), tile);
3073 if (res == CALLBACK_FAILED || !ConvertBooleanCallback(itspec->grf_prop.grffile, CBID_INDTILE_AUTOSLOPE, res)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
3074 } else {
3075 /* allow autoslope */
3076 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
3080 return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
3083 extern const TileTypeProcs _tile_type_industry_procs = {
3084 DrawTile_Industry, // draw_tile_proc
3085 GetSlopePixelZ_Industry, // get_slope_z_proc
3086 ClearTile_Industry, // clear_tile_proc
3087 AddAcceptedCargo_Industry, // add_accepted_cargo_proc
3088 GetTileDesc_Industry, // get_tile_desc_proc
3089 GetTileTrackStatus_Industry, // get_tile_track_status_proc
3090 ClickTile_Industry, // click_tile_proc
3091 AnimateTile_Industry, // animate_tile_proc
3092 TileLoop_Industry, // tile_loop_proc
3093 ChangeTileOwner_Industry, // change_tile_owner_proc
3094 nullptr, // add_produced_cargo_proc
3095 nullptr, // vehicle_enter_tile_proc
3096 GetFoundation_Industry, // get_foundation_proc
3097 TerraformTile_Industry, // terraform_tile_proc
3100 bool IndustryCompare::operator() (const IndustryListEntry &lhs, const IndustryListEntry &rhs) const
3102 /* Compare by distance first and use index as a tiebreaker. */
3103 return std::tie(lhs.distance, lhs.industry->index) < std::tie(rhs.distance, rhs.industry->index);