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/>.
8 /** @file industry_cmd.cpp Handling of industry tiles. */
11 #include "clear_map.h"
13 #include "station_base.h"
14 #include "landscape.h"
15 #include "viewport_func.h"
16 #include "command_func.h"
18 #include "news_func.h"
19 #include "cheat_type.h"
20 #include "company_base.h"
23 #include "newgrf_cargo.h"
24 #include "newgrf_debug.h"
25 #include "newgrf_industrytiles.h"
26 #include "autoslope.h"
28 #include "strings_internal.h"
29 #include "window_func.h"
30 #include "vehicle_func.h"
31 #include "sound_func.h"
32 #include "animated_tile_func.h"
33 #include "effectvehicle_func.h"
34 #include "effectvehicle_base.h"
36 #include "core/pool_func.hpp"
37 #include "subsidy_func.h"
38 #include "core/backup_type.hpp"
39 #include "object_base.h"
40 #include "game/game.hpp"
42 #include "string_func.h"
43 #include "industry_cmd.h"
44 #include "landscape_cmd.h"
45 #include "terraform_cmd.h"
46 #include "timer/timer.h"
47 #include "timer/timer_game_calendar.h"
48 #include "timer/timer_game_economy.h"
49 #include "timer/timer_game_tick.h"
51 #include "table/strings.h"
52 #include "table/industry_land.h"
53 #include "table/build_industry.h"
55 #include "safeguards.h"
57 IndustryPool
_industry_pool("Industry");
58 INSTANTIATE_POOL_METHODS(Industry
)
60 void ShowIndustryViewWindow(int industry
);
61 void BuildOilRig(TileIndex tile
);
63 static uint8_t _industry_sound_ctr
;
64 static TileIndex _industry_sound_tile
;
66 uint16_t Industry::counts
[NUM_INDUSTRYTYPES
];
68 IndustrySpec _industry_specs
[NUM_INDUSTRYTYPES
];
69 IndustryTileSpec _industry_tile_specs
[NUM_INDUSTRYTILES
];
70 IndustryBuildData _industry_builder
; ///< In-game manager of industries.
72 static int WhoCanServiceIndustry(Industry
*ind
);
75 * This function initialize the spec arrays of both
76 * industry and industry tiles.
77 * It adjusts the enabling of the industry too, based on climate availability.
78 * This will allow for clearer testings
80 void ResetIndustries()
82 auto industry_insert
= std::copy(std::begin(_origin_industry_specs
), std::end(_origin_industry_specs
), std::begin(_industry_specs
));
83 std::fill(industry_insert
, std::end(_industry_specs
), IndustrySpec
{});
85 /* Enable only the current climate industries */
86 for (auto it
= std::begin(_industry_specs
); it
!= industry_insert
; ++it
) {
87 it
->enabled
= HasBit(it
->climate_availability
, _settings_game
.game_creation
.landscape
);
90 auto industry_tile_insert
= std::copy(std::begin(_origin_industry_tile_specs
), std::end(_origin_industry_tile_specs
), std::begin(_industry_tile_specs
));
91 std::fill(industry_tile_insert
, std::end(_industry_tile_specs
), IndustryTileSpec
{});
93 /* Reset any overrides that have been set. */
94 _industile_mngr
.ResetOverride();
95 _industry_mngr
.ResetOverride();
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(Tile tile
)
108 assert(IsTileType(tile
, MP_INDUSTRY
));
110 const Industry
*ind
= Industry::GetByTile(tile
);
111 assert(ind
!= nullptr);
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
.base());
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. */
192 DecIndustryTypeCount(this->type
);
194 DeleteIndustryNews(this->index
);
195 CloseWindowById(WC_INDUSTRY_VIEW
, this->index
);
196 DeleteNewGRFInspectWindow(GSF_INDUSTRIES
, this->index
);
198 DeleteSubsidyWith(SourceType::Industry
, this->index
);
199 CargoPacket::InvalidateAllFrom(SourceType::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)
212 InvalidateWindowData(WC_INDUSTRY_DIRECTORY
, 0, IDIWD_FORCE_REBUILD
);
213 SetWindowDirty(WC_BUILD_INDUSTRY
, 0);
218 * Return a random valid industry.
219 * @return random industry, nullptr if there are no industries
221 /* static */ Industry
*Industry::GetRandom()
223 if (Industry::GetNumItems() == 0) return nullptr;
224 int num
= RandomRange((uint16_t)Industry::GetNumItems());
225 size_t index
= MAX_UVALUE(size_t);
231 /* Make sure we have a valid industry */
232 while (!Industry::IsValidID(index
)) {
234 assert(index
< Industry::GetPoolSize());
238 return Industry::Get(index
);
242 static void IndustryDrawSugarMine(const TileInfo
*ti
)
244 if (!IsIndustryCompleted(ti
->tile
)) return;
246 const DrawIndustryAnimationStruct
*d
= &_draw_industry_spec1
[GetAnimationFrame(ti
->tile
)];
248 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_SIEVE
+ d
->image_1
, PAL_NONE
, d
->x
, 0);
250 if (d
->image_2
!= 0) {
251 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_CLOUDS
+ d
->image_2
- 1, PAL_NONE
, 8, 41);
254 if (d
->image_3
!= 0) {
255 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_PILE
+ d
->image_3
- 1, PAL_NONE
,
256 _drawtile_proc1
[d
->image_3
- 1].x
, _drawtile_proc1
[d
->image_3
- 1].y
);
260 static void IndustryDrawToffeeQuarry(const TileInfo
*ti
)
264 if (IsIndustryCompleted(ti
->tile
)) {
265 x
= _industry_anim_offs_toffee
[GetAnimationFrame(ti
->tile
)];
271 AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_SHOVEL
, PAL_NONE
, 22 - x
, 24 + x
);
272 AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_TOFFEE
, PAL_NONE
, 6, 14);
275 static void IndustryDrawBubbleGenerator( const TileInfo
*ti
)
277 if (IsIndustryCompleted(ti
->tile
)) {
278 AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_BUBBLE
, PAL_NONE
, 5, _industry_anim_offs_bubbles
[GetAnimationFrame(ti
->tile
)]);
280 AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_SPRING
, PAL_NONE
, 3, 67);
283 static void IndustryDrawToyFactory(const TileInfo
*ti
)
285 const DrawIndustryAnimationStruct
*d
= &_industry_anim_offs_toys
[GetAnimationFrame(ti
->tile
)];
287 if (d
->image_1
!= 0xFF) {
288 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_CLAY
, PAL_NONE
, d
->x
, 96 + d
->image_1
);
291 if (d
->image_2
!= 0xFF) {
292 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_ROBOT
, PAL_NONE
, 16 - d
->image_2
* 2, 100 + d
->image_2
);
295 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP
, PAL_NONE
, 7, d
->image_3
);
296 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP_HOLDER
, PAL_NONE
, 0, 42);
299 static void IndustryDrawCoalPlantSparks(const TileInfo
*ti
)
301 if (IsIndustryCompleted(ti
->tile
)) {
302 uint8_t image
= GetAnimationFrame(ti
->tile
);
304 if (image
!= 0 && image
< 7) {
305 AddChildSpriteScreen(image
+ SPR_IT_POWER_PLANT_TRANSFORMERS
,
307 _coal_plant_sparks
[image
- 1].x
,
308 _coal_plant_sparks
[image
- 1].y
314 typedef void IndustryDrawTileProc(const TileInfo
*ti
);
315 static IndustryDrawTileProc
* const _industry_draw_tile_procs
[5] = {
316 IndustryDrawSugarMine
,
317 IndustryDrawToffeeQuarry
,
318 IndustryDrawBubbleGenerator
,
319 IndustryDrawToyFactory
,
320 IndustryDrawCoalPlantSparks
,
323 static void DrawTile_Industry(TileInfo
*ti
)
325 IndustryGfx gfx
= GetIndustryGfx(ti
->tile
);
326 Industry
*ind
= Industry::GetByTile(ti
->tile
);
327 const IndustryTileSpec
*indts
= GetIndustryTileSpec(gfx
);
329 /* Retrieve pointer to the draw industry tile struct */
330 if (gfx
>= NEW_INDUSTRYTILEOFFSET
) {
331 /* Draw the tile using the specialized method of newgrf industrytile.
332 * DrawNewIndustry will return false if ever the resolver could not
333 * find any sprite to display. So in this case, we will jump on the
334 * substitute gfx instead. */
335 if (indts
->grf_prop
.spritegroup
[0] != nullptr && DrawNewIndustryTile(ti
, ind
, gfx
, indts
)) {
338 /* No sprite group (or no valid one) found, meaning no graphics associated.
339 * Use the substitute one instead */
340 if (indts
->grf_prop
.subst_id
!= INVALID_INDUSTRYTILE
) {
341 gfx
= indts
->grf_prop
.subst_id
;
342 /* And point the industrytile spec accordingly */
343 indts
= GetIndustryTileSpec(gfx
);
348 const DrawBuildingsTileStruct
*dits
= &_industry_draw_tile_data
[gfx
<< 2 | (indts
->anim_state
?
349 GetAnimationFrame(ti
->tile
) & INDUSTRY_COMPLETED
:
350 GetIndustryConstructionStage(ti
->tile
))];
352 SpriteID image
= dits
->ground
.sprite
;
354 /* DrawFoundation() modifies ti->z and ti->tileh */
355 if (ti
->tileh
!= SLOPE_FLAT
) DrawFoundation(ti
, FOUNDATION_LEVELED
);
357 /* If the ground sprite is the default flat water sprite, draw also canal/river borders.
358 * Do not do this if the tile's WaterClass is 'land'. */
359 if (image
== SPR_FLAT_WATER_TILE
&& IsTileOnWater(ti
->tile
)) {
360 DrawWaterClassGround(ti
);
362 DrawGroundSprite(image
, GroundSpritePaletteTransform(image
, dits
->ground
.pal
, GENERAL_SPRITE_COLOUR(ind
->random_colour
)));
365 /* If industries are transparent and invisible, do not draw the upper part */
366 if (IsInvisibilitySet(TO_INDUSTRIES
)) return;
368 /* Add industry on top of the ground? */
369 image
= dits
->building
.sprite
;
371 AddSortableSpriteToDraw(image
, SpriteLayoutPaletteTransform(image
, dits
->building
.pal
, GENERAL_SPRITE_COLOUR(ind
->random_colour
)),
372 ti
->x
+ dits
->subtile_x
,
373 ti
->y
+ dits
->subtile_y
,
378 IsTransparencySet(TO_INDUSTRIES
));
380 if (IsTransparencySet(TO_INDUSTRIES
)) return;
384 int proc
= dits
->draw_proc
- 1;
385 if (proc
>= 0) _industry_draw_tile_procs
[proc
](ti
);
389 static int GetSlopePixelZ_Industry(TileIndex tile
, uint
, uint
, bool)
391 return GetTileMaxPixelZ(tile
);
394 static Foundation
GetFoundation_Industry(TileIndex tile
, Slope tileh
)
396 IndustryGfx gfx
= GetIndustryGfx(tile
);
398 /* For NewGRF industry tiles we might not be drawing a foundation. We need to
399 * account for this, as other structures should
400 * draw the wall of the foundation in this case.
402 if (gfx
>= NEW_INDUSTRYTILEOFFSET
) {
403 const IndustryTileSpec
*indts
= GetIndustryTileSpec(gfx
);
404 if (indts
->grf_prop
.spritegroup
[0] != nullptr && HasBit(indts
->callback_mask
, CBM_INDT_DRAW_FOUNDATIONS
)) {
405 uint32_t callback_res
= GetIndustryTileCallback(CBID_INDTILE_DRAW_FOUNDATIONS
, 0, 0, gfx
, Industry::GetByTile(tile
), tile
);
406 if (callback_res
!= CALLBACK_FAILED
&& !ConvertBooleanCallback(indts
->grf_prop
.grffile
, CBID_INDTILE_DRAW_FOUNDATIONS
, callback_res
)) return FOUNDATION_NONE
;
409 return FlatteningFoundation(tileh
);
412 static void AddAcceptedCargo_Industry(TileIndex tile
, CargoArray
&acceptance
, CargoTypes
&always_accepted
)
414 IndustryGfx gfx
= GetIndustryGfx(tile
);
415 const IndustryTileSpec
*itspec
= GetIndustryTileSpec(gfx
);
416 const Industry
*ind
= Industry::GetByTile(tile
);
418 /* Starting point for acceptance */
419 auto accepts_cargo
= itspec
->accepts_cargo
;
420 auto cargo_acceptance
= itspec
->acceptance
;
422 if (itspec
->special_flags
& INDTILE_SPECIAL_ACCEPTS_ALL_CARGO
) {
423 /* Copy all accepted cargoes from industry itself */
424 for (const auto &a
: ind
->accepted
) {
425 auto pos
= std::find(std::begin(accepts_cargo
), std::end(accepts_cargo
), a
.cargo
);
426 if (pos
== std::end(accepts_cargo
)) {
427 /* Not found, insert */
428 pos
= std::find(std::begin(accepts_cargo
), std::end(accepts_cargo
), INVALID_CARGO
);
429 if (pos
== std::end(accepts_cargo
)) continue; // nowhere to place, give up on this one
432 cargo_acceptance
[std::distance(std::begin(accepts_cargo
), pos
)] += 8;
436 if (HasBit(itspec
->callback_mask
, CBM_INDT_ACCEPT_CARGO
)) {
437 /* Try callback for accepts list, if success override all existing accepts */
438 uint16_t res
= GetIndustryTileCallback(CBID_INDTILE_ACCEPT_CARGO
, 0, 0, gfx
, Industry::GetByTile(tile
), tile
);
439 if (res
!= CALLBACK_FAILED
) {
440 accepts_cargo
.fill(INVALID_CARGO
);
441 for (uint i
= 0; i
< INDUSTRY_ORIGINAL_NUM_INPUTS
; i
++) accepts_cargo
[i
] = GetCargoTranslation(GB(res
, i
* 5, 5), itspec
->grf_prop
.grffile
);
445 if (HasBit(itspec
->callback_mask
, CBM_INDT_CARGO_ACCEPTANCE
)) {
446 /* Try callback for acceptance list, if success override all existing acceptance */
447 uint16_t res
= GetIndustryTileCallback(CBID_INDTILE_CARGO_ACCEPTANCE
, 0, 0, gfx
, Industry::GetByTile(tile
), tile
);
448 if (res
!= CALLBACK_FAILED
) {
449 cargo_acceptance
.fill(0);
450 for (uint i
= 0; i
< INDUSTRY_ORIGINAL_NUM_INPUTS
; i
++) cargo_acceptance
[i
] = GB(res
, i
* 4, 4);
454 for (uint8_t i
= 0; i
< std::size(itspec
->accepts_cargo
); i
++) {
455 CargoID a
= accepts_cargo
[i
];
456 if (!IsValidCargoID(a
) || cargo_acceptance
[i
] <= 0) continue; // work only with valid cargoes
458 /* Add accepted cargo */
459 acceptance
[a
] += cargo_acceptance
[i
];
461 /* Maybe set 'always accepted' bit (if it's not set already) */
462 if (HasBit(always_accepted
, a
)) continue;
464 /* Test whether the industry itself accepts the cargo type */
465 if (ind
->IsCargoAccepted(a
)) continue;
467 /* If the industry itself doesn't accept this cargo, set 'always accepted' bit */
468 SetBit(always_accepted
, a
);
472 static void GetTileDesc_Industry(TileIndex tile
, TileDesc
*td
)
474 const Industry
*i
= Industry::GetByTile(tile
);
475 const IndustrySpec
*is
= GetIndustrySpec(i
->type
);
477 td
->owner
[0] = i
->owner
;
479 if (!IsIndustryCompleted(tile
)) {
480 td
->dparam
= td
->str
;
481 td
->str
= STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION
;
484 if (is
->grf_prop
.grffile
!= nullptr) {
485 td
->grf
= GetGRFConfig(is
->grf_prop
.grffile
->grfid
)->GetName();
489 static CommandCost
ClearTile_Industry(TileIndex tile
, DoCommandFlag flags
)
491 Industry
*i
= Industry::GetByTile(tile
);
492 const IndustrySpec
*indspec
= GetIndustrySpec(i
->type
);
494 /* water can destroy industries
495 * in editor you can bulldoze industries
496 * with magic_bulldozer cheat you can destroy industries
497 * (area around OILRIG is water, so water shouldn't flood it
499 if ((_current_company
!= OWNER_WATER
&& _game_mode
!= GM_EDITOR
&&
500 !_cheats
.magic_bulldozer
.value
) ||
501 ((flags
& DC_AUTO
) != 0) ||
502 (_current_company
== OWNER_WATER
&&
503 ((indspec
->behaviour
& INDUSTRYBEH_BUILT_ONWATER
) ||
504 HasBit(GetIndustryTileSpec(GetIndustryGfx(tile
))->slopes_refused
, 5)))) {
505 SetDParam(1, indspec
->name
);
506 return_cmd_error(flags
& DC_AUTO
? STR_ERROR_GENERIC_OBJECT_IN_THE_WAY
: INVALID_STRING_ID
);
509 if (flags
& DC_EXEC
) {
510 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i
->index
));
511 Game::NewEvent(new ScriptEventIndustryClose(i
->index
));
514 return CommandCost(EXPENSES_CONSTRUCTION
, indspec
->GetRemovalCost());
518 * Move produced cargo from industry to nearby stations.
519 * @param tile Industry tile
520 * @return true if any cargo was moved.
522 static bool TransportIndustryGoods(TileIndex tile
)
524 Industry
*i
= Industry::GetByTile(tile
);
525 const IndustrySpec
*indspec
= GetIndustrySpec(i
->type
);
526 bool moved_cargo
= false;
528 for (auto &p
: i
->produced
) {
529 uint cw
= ClampTo
<uint8_t>(p
.waiting
);
530 if (cw
> indspec
->minimal_cargo
&& IsValidCargoID(p
.cargo
)) {
533 /* fluctuating economy? */
534 if (EconomyIsInRecession()) cw
= (cw
+ 1) / 2;
536 p
.history
[THIS_MONTH
].production
+= cw
;
538 uint am
= MoveGoodsToStation(p
.cargo
, cw
, SourceType::Industry
, i
->index
, &i
->stations_near
, i
->exclusive_consumer
);
539 p
.history
[THIS_MONTH
].transported
+= am
;
541 moved_cargo
|= (am
!= 0);
548 static void AnimateSugarSieve(TileIndex tile
)
550 uint8_t m
= GetAnimationFrame(tile
) + 1;
552 if (_settings_client
.sound
.ambient
) {
554 case 2: SndPlayTileFx(SND_2D_SUGAR_MINE_1
, tile
); break;
555 case 6: SndPlayTileFx(SND_29_SUGAR_MINE_2
, tile
); break;
561 DeleteAnimatedTile(tile
);
563 SetAnimationFrame(tile
, m
);
565 MarkTileDirtyByTile(tile
);
568 static void AnimateToffeeQuarry(TileIndex tile
)
570 uint8_t m
= GetAnimationFrame(tile
);
572 if (_industry_anim_offs_toffee
[m
] == 0xFF && _settings_client
.sound
.ambient
) {
573 SndPlayTileFx(SND_30_TOFFEE_QUARRY
, tile
);
578 DeleteAnimatedTile(tile
);
580 SetAnimationFrame(tile
, m
);
582 MarkTileDirtyByTile(tile
);
585 static void AnimateBubbleCatcher(TileIndex tile
)
587 uint8_t m
= GetAnimationFrame(tile
);
591 DeleteAnimatedTile(tile
);
593 SetAnimationFrame(tile
, m
);
595 MarkTileDirtyByTile(tile
);
598 static void AnimatePowerPlantSparks(TileIndex tile
)
600 uint8_t m
= GetAnimationFrame(tile
);
602 SetAnimationFrame(tile
, 0);
603 DeleteAnimatedTile(tile
);
605 SetAnimationFrame(tile
, m
+ 1);
607 MarkTileDirtyByTile(tile
);
610 static void AnimateToyFactory(TileIndex tile
)
612 uint8_t m
= GetAnimationFrame(tile
) + 1;
615 case 1: if (_settings_client
.sound
.ambient
) SndPlayTileFx(SND_2C_TOY_FACTORY_1
, tile
); break;
616 case 23: if (_settings_client
.sound
.ambient
) SndPlayTileFx(SND_2B_TOY_FACTORY_2
, tile
); break;
617 case 28: if (_settings_client
.sound
.ambient
) SndPlayTileFx(SND_2A_TOY_FACTORY_3
, tile
); break;
620 int n
= GetIndustryAnimationLoop(tile
) + 1;
624 DeleteAnimatedTile(tile
);
626 SetIndustryAnimationLoop(tile
, n
);
630 SetAnimationFrame(tile
, m
);
631 MarkTileDirtyByTile(tile
);
634 static void AnimatePlasticFountain(TileIndex tile
, IndustryGfx gfx
)
636 gfx
= (gfx
< GFX_PLASTIC_FOUNTAIN_ANIMATED_8
) ? gfx
+ 1 : GFX_PLASTIC_FOUNTAIN_ANIMATED_1
;
637 SetIndustryGfx(tile
, gfx
);
638 MarkTileDirtyByTile(tile
);
641 static void AnimateOilWell(TileIndex tile
, IndustryGfx gfx
)
643 bool b
= Chance16(1, 7);
644 uint8_t m
= GetAnimationFrame(tile
) + 1;
645 if (m
== 4 && (m
= 0, ++gfx
) == GFX_OILWELL_ANIMATED_3
+ 1 && (gfx
= GFX_OILWELL_ANIMATED_1
, b
)) {
646 SetIndustryGfx(tile
, GFX_OILWELL_NOT_ANIMATED
);
647 SetIndustryConstructionStage(tile
, 3);
648 DeleteAnimatedTile(tile
);
650 SetAnimationFrame(tile
, m
);
651 SetIndustryGfx(tile
, gfx
);
653 MarkTileDirtyByTile(tile
);
656 static void AnimateMineTower(TileIndex tile
)
658 int state
= TimerGameTick::counter
& 0x7FF;
660 if ((state
-= 0x400) < 0) return;
663 if (state
< 0x20 || state
>= 0x180) {
664 uint8_t m
= GetAnimationFrame(tile
);
666 SetAnimationFrame(tile
, m
| 0x40);
667 if (_settings_client
.sound
.ambient
) SndPlayTileFx(SND_0B_MINE
, tile
);
669 if (state
& 7) return;
671 if (state
& 3) return;
673 uint8_t m
= (GetAnimationFrame(tile
) + 1) | 0x40;
674 if (m
> 0xC2) m
= 0xC0;
675 SetAnimationFrame(tile
, m
);
676 MarkTileDirtyByTile(tile
);
677 } else if (state
>= 0x200 && state
< 0x3A0) {
678 int i
= (state
< 0x220 || state
>= 0x380) ? 7 : 3;
679 if (state
& i
) return;
681 uint8_t m
= (GetAnimationFrame(tile
) & 0xBF) - 1;
682 if (m
< 0x80) m
= 0x82;
683 SetAnimationFrame(tile
, m
);
684 MarkTileDirtyByTile(tile
);
688 static void AnimateTile_Industry(TileIndex tile
)
690 IndustryGfx gfx
= GetIndustryGfx(tile
);
692 if (GetIndustryTileSpec(gfx
)->animation
.status
!= ANIM_STATUS_NO_ANIMATION
) {
693 AnimateNewIndustryTile(tile
);
698 case GFX_SUGAR_MINE_SIEVE
:
699 if ((TimerGameTick::counter
& 1) == 0) AnimateSugarSieve(tile
);
702 case GFX_TOFFEE_QUARY
:
703 if ((TimerGameTick::counter
& 3) == 0) AnimateToffeeQuarry(tile
);
706 case GFX_BUBBLE_CATCHER
:
707 if ((TimerGameTick::counter
& 1) == 0) AnimateBubbleCatcher(tile
);
710 case GFX_POWERPLANT_SPARKS
:
711 if ((TimerGameTick::counter
& 3) == 0) AnimatePowerPlantSparks(tile
);
714 case GFX_TOY_FACTORY
:
715 if ((TimerGameTick::counter
& 1) == 0) AnimateToyFactory(tile
);
718 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1
: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2
:
719 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3
: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4
:
720 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5
: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6
:
721 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7
: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8
:
722 if ((TimerGameTick::counter
& 3) == 0) AnimatePlasticFountain(tile
, gfx
);
725 case GFX_OILWELL_ANIMATED_1
:
726 case GFX_OILWELL_ANIMATED_2
:
727 case GFX_OILWELL_ANIMATED_3
:
728 if ((TimerGameTick::counter
& 7) == 0) AnimateOilWell(tile
, gfx
);
731 case GFX_COAL_MINE_TOWER_ANIMATED
:
732 case GFX_COPPER_MINE_TOWER_ANIMATED
:
733 case GFX_GOLD_MINE_TOWER_ANIMATED
:
734 AnimateMineTower(tile
);
739 static void CreateChimneySmoke(TileIndex tile
)
741 uint x
= TileX(tile
) * TILE_SIZE
;
742 uint y
= TileY(tile
) * TILE_SIZE
;
743 int z
= GetTileMaxPixelZ(tile
);
745 CreateEffectVehicle(x
+ 15, y
+ 14, z
+ 59, EV_CHIMNEY_SMOKE
);
748 static void MakeIndustryTileBigger(TileIndex tile
)
750 uint8_t cnt
= GetIndustryConstructionCounter(tile
) + 1;
752 SetIndustryConstructionCounter(tile
, cnt
);
756 uint8_t stage
= GetIndustryConstructionStage(tile
) + 1;
757 SetIndustryConstructionCounter(tile
, 0);
758 SetIndustryConstructionStage(tile
, stage
);
759 StartStopIndustryTileAnimation(tile
, IAT_CONSTRUCTION_STATE_CHANGE
);
760 if (stage
== INDUSTRY_COMPLETED
) SetIndustryCompleted(tile
);
762 MarkTileDirtyByTile(tile
);
764 if (!IsIndustryCompleted(tile
)) return;
766 IndustryGfx gfx
= GetIndustryGfx(tile
);
767 if (gfx
>= NEW_INDUSTRYTILEOFFSET
) {
768 /* New industries are already animated on construction. */
773 case GFX_POWERPLANT_CHIMNEY
:
774 CreateChimneySmoke(tile
);
778 /* Do not require an industry tile to be after the first two GFX_OILRIG_1
779 * tiles (like the default oil rig). Do a proper check to ensure the
780 * tiles belong to the same industry and based on that build the oil rig's
782 TileIndex other
= tile
+ TileDiffXY(0, 1);
784 if (IsTileType(other
, MP_INDUSTRY
) &&
785 GetIndustryGfx(other
) == GFX_OILRIG_1
&&
786 GetIndustryIndex(tile
) == GetIndustryIndex(other
)) {
792 case GFX_TOY_FACTORY
:
793 case GFX_BUBBLE_CATCHER
:
794 case GFX_TOFFEE_QUARY
:
795 SetAnimationFrame(tile
, 0);
796 SetIndustryAnimationLoop(tile
, 0);
799 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1
: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2
:
800 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3
: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4
:
801 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5
: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6
:
802 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7
: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8
:
803 AddAnimatedTile(tile
, false);
808 static void TileLoopIndustry_BubbleGenerator(TileIndex tile
)
810 static const int8_t _bubble_spawn_location
[3][4] = {
816 if (_settings_client
.sound
.ambient
) SndPlayTileFx(SND_2E_BUBBLE_GENERATOR
, tile
);
818 int dir
= Random() & 3;
820 EffectVehicle
*v
= CreateEffectVehicleAbove(
821 TileX(tile
) * TILE_SIZE
+ _bubble_spawn_location
[0][dir
],
822 TileY(tile
) * TILE_SIZE
+ _bubble_spawn_location
[1][dir
],
823 _bubble_spawn_location
[2][dir
],
827 if (v
!= nullptr) v
->animation_substate
= dir
;
830 static void TileLoop_Industry(TileIndex tile
)
832 if (IsTileOnWater(tile
)) TileLoop_Water(tile
);
834 /* Normally this doesn't happen, but if an industry NewGRF is removed
835 * an industry that was previously build on water can now be flooded.
836 * If this happens the tile is no longer an industry tile after
837 * returning from TileLoop_Water. */
838 if (!IsTileType(tile
, MP_INDUSTRY
)) return;
840 TriggerIndustryTile(tile
, INDTILE_TRIGGER_TILE_LOOP
);
842 if (!IsIndustryCompleted(tile
)) {
843 MakeIndustryTileBigger(tile
);
847 if (_game_mode
== GM_EDITOR
) return;
849 if (TransportIndustryGoods(tile
) && !StartStopIndustryTileAnimation(Industry::GetByTile(tile
), IAT_INDUSTRY_DISTRIBUTES_CARGO
)) {
850 uint newgfx
= GetIndustryTileSpec(GetIndustryGfx(tile
))->anim_production
;
852 if (newgfx
!= INDUSTRYTILE_NOANIM
) {
853 ResetIndustryConstructionStage(tile
);
854 SetIndustryCompleted(tile
);
855 SetIndustryGfx(tile
, newgfx
);
856 MarkTileDirtyByTile(tile
);
861 if (StartStopIndustryTileAnimation(tile
, IAT_TILELOOP
)) return;
863 IndustryGfx newgfx
= GetIndustryTileSpec(GetIndustryGfx(tile
))->anim_next
;
864 if (newgfx
!= INDUSTRYTILE_NOANIM
) {
865 ResetIndustryConstructionStage(tile
);
866 SetIndustryGfx(tile
, newgfx
);
867 MarkTileDirtyByTile(tile
);
871 IndustryGfx gfx
= GetIndustryGfx(tile
);
873 case GFX_COAL_MINE_TOWER_NOT_ANIMATED
:
874 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED
:
875 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED
:
876 if (!(TimerGameTick::counter
& 0x400) && Chance16(1, 2)) {
878 case GFX_COAL_MINE_TOWER_NOT_ANIMATED
: gfx
= GFX_COAL_MINE_TOWER_ANIMATED
; break;
879 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED
: gfx
= GFX_COPPER_MINE_TOWER_ANIMATED
; break;
880 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED
: gfx
= GFX_GOLD_MINE_TOWER_ANIMATED
; break;
882 SetIndustryGfx(tile
, gfx
);
883 SetAnimationFrame(tile
, 0x80);
884 AddAnimatedTile(tile
);
888 case GFX_OILWELL_NOT_ANIMATED
:
889 if (Chance16(1, 6)) {
890 SetIndustryGfx(tile
, GFX_OILWELL_ANIMATED_1
);
891 SetAnimationFrame(tile
, 0);
892 AddAnimatedTile(tile
);
896 case GFX_COAL_MINE_TOWER_ANIMATED
:
897 case GFX_COPPER_MINE_TOWER_ANIMATED
:
898 case GFX_GOLD_MINE_TOWER_ANIMATED
:
899 if (!(TimerGameTick::counter
& 0x400)) {
901 case GFX_COAL_MINE_TOWER_ANIMATED
: gfx
= GFX_COAL_MINE_TOWER_NOT_ANIMATED
; break;
902 case GFX_COPPER_MINE_TOWER_ANIMATED
: gfx
= GFX_COPPER_MINE_TOWER_NOT_ANIMATED
; break;
903 case GFX_GOLD_MINE_TOWER_ANIMATED
: gfx
= GFX_GOLD_MINE_TOWER_NOT_ANIMATED
; break;
905 SetIndustryGfx(tile
, gfx
);
906 SetIndustryCompleted(tile
);
907 SetIndustryConstructionStage(tile
, 3);
908 DeleteAnimatedTile(tile
);
909 MarkTileDirtyByTile(tile
);
913 case GFX_POWERPLANT_SPARKS
:
914 if (Chance16(1, 3)) {
915 if (_settings_client
.sound
.ambient
) SndPlayTileFx(SND_0C_POWER_STATION
, tile
);
916 AddAnimatedTile(tile
);
920 case GFX_COPPER_MINE_CHIMNEY
:
921 CreateEffectVehicleAbove(TileX(tile
) * TILE_SIZE
+ 6, TileY(tile
) * TILE_SIZE
+ 6, 43, EV_COPPER_MINE_SMOKE
);
925 case GFX_TOY_FACTORY
: {
926 Industry
*i
= Industry::GetByTile(tile
);
927 if (i
->was_cargo_delivered
) {
928 i
->was_cargo_delivered
= false;
929 SetIndustryAnimationLoop(tile
, 0);
930 AddAnimatedTile(tile
);
935 case GFX_BUBBLE_GENERATOR
:
936 TileLoopIndustry_BubbleGenerator(tile
);
939 case GFX_TOFFEE_QUARY
:
940 AddAnimatedTile(tile
);
943 case GFX_SUGAR_MINE_SIEVE
:
944 if (Chance16(1, 3)) AddAnimatedTile(tile
);
949 static bool ClickTile_Industry(TileIndex tile
)
951 ShowIndustryViewWindow(GetIndustryIndex(tile
));
955 static TrackStatus
GetTileTrackStatus_Industry(TileIndex
, TransportType
, uint
, DiagDirection
)
960 static void ChangeTileOwner_Industry(TileIndex tile
, Owner old_owner
, Owner new_owner
)
962 /* If the founder merges, the industry was created by the merged company */
963 Industry
*i
= Industry::GetByTile(tile
);
964 if (i
->founder
== old_owner
) i
->founder
= (new_owner
== INVALID_OWNER
) ? OWNER_NONE
: new_owner
;
966 if (i
->exclusive_supplier
== old_owner
) i
->exclusive_supplier
= new_owner
;
967 if (i
->exclusive_consumer
== old_owner
) i
->exclusive_consumer
= new_owner
;
971 * Check whether the tile is a forest.
972 * @param tile the tile to investigate.
973 * @return true if and only if the tile is a forest
975 bool IsTileForestIndustry(TileIndex tile
)
977 /* Check for industry tile */
978 if (!IsTileType(tile
, MP_INDUSTRY
)) return false;
980 const Industry
*ind
= Industry::GetByTile(tile
);
982 /* Check for organic industry (i.e. not processing or extractive) */
983 if ((GetIndustrySpec(ind
->type
)->life_type
& INDUSTRYLIFE_ORGANIC
) == 0) return false;
985 /* Check for wood production */
986 return std::any_of(std::begin(ind
->produced
), std::end(ind
->produced
), [](const auto &p
) { return IsValidCargoID(p
.cargo
) && CargoSpec::Get(p
.cargo
)->label
== CT_WOOD
; });
989 static const uint8_t _plantfarmfield_type
[] = {1, 1, 1, 1, 1, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6};
992 * Check whether the tile can be replaced by a farm field.
993 * @param tile the tile to investigate.
994 * @param allow_fields if true, the method will return true even if
995 * the tile is a farm tile, otherwise the tile may not be a farm tile
996 * @return true if the tile can become a farm field
998 static bool IsSuitableForFarmField(TileIndex tile
, bool allow_fields
)
1000 switch (GetTileType(tile
)) {
1001 case MP_CLEAR
: return !IsClearGround(tile
, CLEAR_SNOW
) && !IsClearGround(tile
, CLEAR_DESERT
) && (allow_fields
|| !IsClearGround(tile
, CLEAR_FIELDS
));
1002 case MP_TREES
: return GetTreeGround(tile
) != TREE_GROUND_SHORE
;
1003 default: return false;
1008 * Build farm field fence
1009 * @param tile the tile to position the fence on
1010 * @param size the size of the field being planted in tiles
1011 * @param type type of fence to set
1012 * @param side the side of the tile to attempt placement
1014 static void SetupFarmFieldFence(TileIndex tile
, int size
, uint8_t type
, DiagDirection side
)
1016 TileIndexDiff diff
= TileOffsByAxis(OtherAxis(DiagDirToAxis(side
)));
1017 TileIndexDiff neighbour_diff
= TileOffsByDiagDir(side
);
1020 tile
= Map::WrapToMap(tile
);
1022 if (IsTileType(tile
, MP_CLEAR
) && IsClearGround(tile
, CLEAR_FIELDS
)) {
1023 TileIndex neighbour
= tile
+ neighbour_diff
;
1024 if (!IsTileType(neighbour
, MP_CLEAR
) || !IsClearGround(neighbour
, CLEAR_FIELDS
) || GetFence(neighbour
, ReverseDiagDir(side
)) == 0) {
1025 /* Add fence as long as neighbouring tile does not already have a fence in the same position. */
1028 if (or_
== 1 && Chance16(1, 7)) or_
= 2;
1030 SetFence(tile
, side
, or_
);
1038 static void PlantFarmField(TileIndex tile
, IndustryID industry
)
1040 if (_settings_game
.game_creation
.landscape
== LT_ARCTIC
) {
1041 if (GetTileZ(tile
) + 2 >= GetSnowLine()) return;
1044 /* determine field size */
1045 uint32_t r
= (Random() & 0x303) + 0x404;
1046 if (_settings_game
.game_creation
.landscape
== LT_ARCTIC
) r
+= 0x404;
1047 uint size_x
= GB(r
, 0, 8);
1048 uint size_y
= GB(r
, 8, 8);
1050 TileArea
ta(tile
- TileDiffXY(std::min(TileX(tile
), size_x
/ 2), std::min(TileY(tile
), size_y
/ 2)), size_x
, size_y
);
1053 if (ta
.w
== 0 || ta
.h
== 0) return;
1055 /* check the amount of bad tiles */
1057 for (TileIndex cur_tile
: ta
) {
1058 assert(cur_tile
< Map::Size());
1059 count
+= IsSuitableForFarmField(cur_tile
, false);
1061 if (count
* 2 < ta
.w
* ta
.h
) return;
1063 /* determine type of field */
1065 uint counter
= GB(r
, 5, 3);
1066 uint field_type
= GB(r
, 8, 8) * 9 >> 8;
1069 for (TileIndex cur_tile
: ta
) {
1070 assert(cur_tile
< Map::Size());
1071 if (IsSuitableForFarmField(cur_tile
, true)) {
1072 MakeField(cur_tile
, field_type
, industry
);
1073 SetClearCounter(cur_tile
, counter
);
1074 MarkTileDirtyByTile(cur_tile
);
1079 if (_settings_game
.game_creation
.landscape
!= LT_ARCTIC
&& _settings_game
.game_creation
.landscape
!= LT_TROPIC
) {
1080 type
= _plantfarmfield_type
[Random() & 0xF];
1083 SetupFarmFieldFence(ta
.tile
, ta
.h
, type
, DIAGDIR_NE
);
1084 SetupFarmFieldFence(ta
.tile
, ta
.w
, type
, DIAGDIR_NW
);
1085 SetupFarmFieldFence(ta
.tile
+ TileDiffXY(ta
.w
- 1, 0), ta
.h
, type
, DIAGDIR_SW
);
1086 SetupFarmFieldFence(ta
.tile
+ TileDiffXY(0, ta
.h
- 1), ta
.w
, type
, DIAGDIR_SE
);
1089 void PlantRandomFarmField(const Industry
*i
)
1091 int x
= i
->location
.w
/ 2 + Random() % 31 - 16;
1092 int y
= i
->location
.h
/ 2 + Random() % 31 - 16;
1094 TileIndex tile
= TileAddWrap(i
->location
.tile
, x
, y
);
1096 if (tile
!= INVALID_TILE
) PlantFarmField(tile
, i
->index
);
1100 * Search callback function for ChopLumberMillTrees
1101 * @param tile to test
1102 * @return the result of the test
1104 static bool SearchLumberMillTrees(TileIndex tile
, void *)
1106 if (IsTileType(tile
, MP_TREES
) && GetTreeGrowth(tile
) >= TreeGrowthStage::Grown
) {
1109 Backup
<CompanyID
> cur_company(_current_company
, OWNER_NONE
);
1111 _industry_sound_ctr
= 1;
1112 _industry_sound_tile
= tile
;
1113 if (_settings_client
.sound
.ambient
) SndPlayTileFx(SND_38_LUMBER_MILL_1
, tile
);
1115 Command
<CMD_LANDSCAPE_CLEAR
>::Do(DC_EXEC
, tile
);
1117 cur_company
.Restore();
1124 * Perform a circular search around the Lumber Mill in order to find trees to cut
1127 static void ChopLumberMillTrees(Industry
*i
)
1129 /* Don't process lumber mill if cargo is not set up correctly. */
1130 auto itp
= std::begin(i
->produced
);
1131 if (itp
== std::end(i
->produced
) || !IsValidCargoID(itp
->cargo
)) return;
1133 /* We only want to cut trees if all tiles are completed. */
1134 for (TileIndex tile_cur
: i
->location
) {
1135 if (i
->TileBelongsToIndustry(tile_cur
)) {
1136 if (!IsIndustryCompleted(tile_cur
)) return;
1140 TileIndex tile
= i
->location
.tile
;
1141 if (CircularTileSearch(&tile
, 40, SearchLumberMillTrees
, nullptr)) { // 40x40 tiles to search.
1142 itp
->waiting
= ClampTo
<uint16_t>(itp
->waiting
+ ScaleByCargoScale(45, false)); // Found a tree, add according value to waiting cargo.
1147 * Helper for ProduceIndustryGoods that scales and produces cargos.
1148 * @param i The industry
1149 * @param scale Should we scale production of this cargo directly?
1151 static void ProduceIndustryGoodsHelper(Industry
*i
, bool scale
)
1153 for (auto &p
: i
->produced
) {
1154 if (!IsValidCargoID(p
.cargo
)) continue;
1156 uint16_t amount
= p
.rate
;
1157 if (scale
) amount
= ScaleByCargoScale(amount
, false);
1159 p
.waiting
= ClampTo
<uint16_t>(p
.waiting
+ amount
);
1163 static void ProduceIndustryGoods(Industry
*i
)
1165 const IndustrySpec
*indsp
= GetIndustrySpec(i
->type
);
1168 if ((i
->counter
& 0x3F) == 0) {
1170 if (Chance16R(1, 14, r
) && !indsp
->random_sounds
.empty() && _settings_client
.sound
.ambient
) {
1171 if (std::any_of(std::begin(i
->produced
), std::end(i
->produced
), [](const auto &p
) { return p
.history
[LAST_MONTH
].production
> 0; })) {
1172 /* Play sound since last month had production */
1174 static_cast<SoundFx
>(indsp
->random_sounds
[((r
>> 16) * indsp
->random_sounds
.size()) >> 16]),
1182 /* If using an industry callback, scale the callback interval by cargo scale percentage. */
1183 if (HasBit(indsp
->callback_mask
, CBM_IND_PRODUCTION_256_TICKS
)) {
1184 if (i
->counter
% ScaleByInverseCargoScale(Ticks::INDUSTRY_PRODUCE_TICKS
, false) == 0) {
1185 IndustryProductionCallback(i
, 1);
1186 ProduceIndustryGoodsHelper(i
, false);
1191 * All other production and special effects happen every 256 ticks, and cargo production is just scaled by the cargo scale percentage.
1192 * This keeps a slow trickle of production to avoid confusion at low scale factors when the industry seems to be doing nothing for a long period of time.
1194 if ((i
->counter
% Ticks::INDUSTRY_PRODUCE_TICKS
) == 0) {
1195 /* Handle non-callback cargo production. */
1196 if (!HasBit(indsp
->callback_mask
, CBM_IND_PRODUCTION_256_TICKS
)) ProduceIndustryGoodsHelper(i
, true);
1198 IndustryBehaviour indbehav
= indsp
->behaviour
;
1200 if ((indbehav
& INDUSTRYBEH_PLANT_FIELDS
) != 0) {
1201 uint16_t cb_res
= CALLBACK_FAILED
;
1202 if (HasBit(indsp
->callback_mask
, CBM_IND_SPECIAL_EFFECT
)) {
1203 cb_res
= GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT
, Random(), 0, i
, i
->type
, i
->location
.tile
);
1207 if (cb_res
!= CALLBACK_FAILED
) {
1208 plant
= ConvertBooleanCallback(indsp
->grf_prop
.grffile
, CBID_INDUSTRY_SPECIAL_EFFECT
, cb_res
);
1210 plant
= Chance16(1, 8);
1213 if (plant
) PlantRandomFarmField(i
);
1215 if ((indbehav
& INDUSTRYBEH_CUT_TREES
) != 0) {
1216 uint16_t cb_res
= CALLBACK_FAILED
;
1217 if (HasBit(indsp
->callback_mask
, CBM_IND_SPECIAL_EFFECT
)) {
1218 cb_res
= GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT
, Random(), 1, i
, i
->type
, i
->location
.tile
);
1222 if (cb_res
!= CALLBACK_FAILED
) {
1223 cut
= ConvertBooleanCallback(indsp
->grf_prop
.grffile
, CBID_INDUSTRY_SPECIAL_EFFECT
, cb_res
);
1225 cut
= ((i
->counter
% Ticks::INDUSTRY_CUT_TREE_TICKS
) == 0);
1228 if (cut
) ChopLumberMillTrees(i
);
1231 TriggerIndustry(i
, INDUSTRY_TRIGGER_INDUSTRY_TICK
);
1232 StartStopIndustryTileAnimation(i
, IAT_INDUSTRY_TICK
);
1236 void OnTick_Industry()
1238 if (_industry_sound_ctr
!= 0) {
1239 _industry_sound_ctr
++;
1241 if (_industry_sound_ctr
== 75) {
1242 if (_settings_client
.sound
.ambient
) SndPlayTileFx(SND_37_LUMBER_MILL_2
, _industry_sound_tile
);
1243 } else if (_industry_sound_ctr
== 160) {
1244 _industry_sound_ctr
= 0;
1245 if (_settings_client
.sound
.ambient
) SndPlayTileFx(SND_36_LUMBER_MILL_3
, _industry_sound_tile
);
1249 if (_game_mode
== GM_EDITOR
) return;
1251 for (Industry
*i
: Industry::Iterate()) {
1252 ProduceIndustryGoods(i
);
1257 * Check the conditions of #CHECK_NOTHING (Always succeeds).
1258 * @return Succeeded or failed command.
1260 static CommandCost
CheckNewIndustry_NULL(TileIndex
)
1262 return CommandCost();
1266 * Check the conditions of #CHECK_FOREST (Industry should be build above snow-line in arctic climate).
1267 * @param tile %Tile to perform the checking.
1268 * @return Succeeded or failed command.
1270 static CommandCost
CheckNewIndustry_Forest(TileIndex tile
)
1272 if (_settings_game
.game_creation
.landscape
== LT_ARCTIC
) {
1273 if (GetTileZ(tile
) < HighestSnowLine() + 2) {
1274 return_cmd_error(STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED
);
1277 return CommandCost();
1281 * Check if a tile is within a distance from map edges, scaled by map dimensions independently.
1282 * Each dimension is checked independently, and dimensions smaller than 256 are not scaled.
1283 * @param tile Which tile to check distance of.
1284 * @param maxdist Normal distance on a 256x256 map.
1285 * @return True if the tile is near the map edge.
1287 static bool CheckScaledDistanceFromEdge(TileIndex tile
, uint maxdist
)
1289 uint maxdist_x
= maxdist
;
1290 uint maxdist_y
= maxdist
;
1292 if (Map::SizeX() > 256) maxdist_x
*= Map::SizeX() / 256;
1293 if (Map::SizeY() > 256) maxdist_y
*= Map::SizeY() / 256;
1295 if (DistanceFromEdgeDir(tile
, DIAGDIR_NE
) < maxdist_x
) return true;
1296 if (DistanceFromEdgeDir(tile
, DIAGDIR_NW
) < maxdist_y
) return true;
1297 if (DistanceFromEdgeDir(tile
, DIAGDIR_SW
) < maxdist_x
) return true;
1298 if (DistanceFromEdgeDir(tile
, DIAGDIR_SE
) < maxdist_y
) return true;
1304 * Check the conditions of #CHECK_REFINERY (Industry should be positioned near edge of the map).
1305 * @param tile %Tile to perform the checking.
1306 * @return Succeeded or failed command.
1308 static CommandCost
CheckNewIndustry_OilRefinery(TileIndex tile
)
1310 if (_game_mode
== GM_EDITOR
) return CommandCost();
1312 if (CheckScaledDistanceFromEdge(TileAddXY(tile
, 1, 1), _settings_game
.game_creation
.oil_refinery_limit
)) return CommandCost();
1314 return_cmd_error(STR_ERROR_CAN_ONLY_BE_POSITIONED
);
1317 extern bool _ignore_restrictions
;
1320 * Check the conditions of #CHECK_OIL_RIG (Industries at sea should be positioned near edge of the map).
1321 * @param tile %Tile to perform the checking.
1322 * @return Succeeded or failed command.
1324 static CommandCost
CheckNewIndustry_OilRig(TileIndex tile
)
1326 if (_game_mode
== GM_EDITOR
&& _ignore_restrictions
) return CommandCost();
1328 if (TileHeight(tile
) == 0 &&
1329 CheckScaledDistanceFromEdge(TileAddXY(tile
, 1, 1), _settings_game
.game_creation
.oil_refinery_limit
)) return CommandCost();
1331 return_cmd_error(STR_ERROR_CAN_ONLY_BE_POSITIONED
);
1335 * Check the conditions of #CHECK_FARM (Industry should be below snow-line in arctic).
1336 * @param tile %Tile to perform the checking.
1337 * @return Succeeded or failed command.
1339 static CommandCost
CheckNewIndustry_Farm(TileIndex tile
)
1341 if (_settings_game
.game_creation
.landscape
== LT_ARCTIC
) {
1342 if (GetTileZ(tile
) + 2 >= HighestSnowLine()) {
1343 return_cmd_error(STR_ERROR_SITE_UNSUITABLE
);
1346 return CommandCost();
1350 * Check the conditions of #CHECK_PLANTATION (Industry should NOT be in the desert).
1351 * @param tile %Tile to perform the checking.
1352 * @return Succeeded or failed command.
1354 static CommandCost
CheckNewIndustry_Plantation(TileIndex tile
)
1356 if (GetTropicZone(tile
) == TROPICZONE_DESERT
) {
1357 return_cmd_error(STR_ERROR_SITE_UNSUITABLE
);
1359 return CommandCost();
1363 * Check the conditions of #CHECK_WATER (Industry should be in the desert).
1364 * @param tile %Tile to perform the checking.
1365 * @return Succeeded or failed command.
1367 static CommandCost
CheckNewIndustry_Water(TileIndex tile
)
1369 if (GetTropicZone(tile
) != TROPICZONE_DESERT
) {
1370 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT
);
1372 return CommandCost();
1376 * Check the conditions of #CHECK_LUMBERMILL (Industry should be in the rain forest).
1377 * @param tile %Tile to perform the checking.
1378 * @return Succeeded or failed command.
1380 static CommandCost
CheckNewIndustry_Lumbermill(TileIndex tile
)
1382 if (GetTropicZone(tile
) != TROPICZONE_RAINFOREST
) {
1383 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST
);
1385 return CommandCost();
1389 * Check the conditions of #CHECK_BUBBLEGEN (Industry should be in low land).
1390 * @param tile %Tile to perform the checking.
1391 * @return Succeeded or failed command.
1393 static CommandCost
CheckNewIndustry_BubbleGen(TileIndex tile
)
1395 if (GetTileZ(tile
) > 4) {
1396 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS
);
1398 return CommandCost();
1402 * Industrytype check function signature.
1403 * @param tile %Tile to check.
1404 * @return Succeeded or failed command.
1406 typedef CommandCost
CheckNewIndustryProc(TileIndex tile
);
1408 /** Check functions for different types of industry. */
1409 static CheckNewIndustryProc
* const _check_new_industry_procs
[CHECK_END
] = {
1410 CheckNewIndustry_NULL
, ///< CHECK_NOTHING
1411 CheckNewIndustry_Forest
, ///< CHECK_FOREST
1412 CheckNewIndustry_OilRefinery
, ///< CHECK_REFINERY
1413 CheckNewIndustry_Farm
, ///< CHECK_FARM
1414 CheckNewIndustry_Plantation
, ///< CHECK_PLANTATION
1415 CheckNewIndustry_Water
, ///< CHECK_WATER
1416 CheckNewIndustry_Lumbermill
, ///< CHECK_LUMBERMILL
1417 CheckNewIndustry_BubbleGen
, ///< CHECK_BUBBLEGEN
1418 CheckNewIndustry_OilRig
, ///< CHECK_OIL_RIG
1422 * Find a town for the industry, while checking for multiple industries in the same town.
1423 * @param tile Position of the industry to build.
1424 * @param type Industry type.
1425 * @param[out] t Pointer to return town for the new industry, \c nullptr is written if no good town can be found.
1426 * @return Succeeded or failed command.
1428 * @pre \c *t != nullptr
1429 * @post \c *t points to a town on success, and \c nullptr on failure.
1431 static CommandCost
FindTownForIndustry(TileIndex tile
, int type
, Town
**t
)
1433 *t
= ClosestTownFromTile(tile
, UINT_MAX
);
1435 if (_settings_game
.economy
.multiple_industry_per_town
) return CommandCost();
1437 for (const Industry
*i
: Industry::Iterate()) {
1438 if (i
->type
== (uint8_t)type
&& i
->town
== *t
) {
1440 return_cmd_error(STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN
);
1444 return CommandCost();
1447 bool IsSlopeRefused(Slope current
, Slope refused
)
1449 if (IsSteepSlope(current
)) return true;
1450 if (current
!= SLOPE_FLAT
) {
1451 if (IsSteepSlope(refused
)) return true;
1453 Slope t
= ComplementSlope(current
);
1455 if ((refused
& SLOPE_W
) && (t
& SLOPE_NW
)) return true;
1456 if ((refused
& SLOPE_S
) && (t
& SLOPE_NE
)) return true;
1457 if ((refused
& SLOPE_E
) && (t
& SLOPE_SW
)) return true;
1458 if ((refused
& SLOPE_N
) && (t
& SLOPE_SE
)) return true;
1465 * Are the tiles of the industry free?
1466 * @param tile Position to check.
1467 * @param layout Industry tiles table.
1468 * @param type Type of the industry.
1469 * @return Failed or succeeded command.
1471 static CommandCost
CheckIfIndustryTilesAreFree(TileIndex tile
, const IndustryTileLayout
&layout
, IndustryType type
)
1473 IndustryBehaviour ind_behav
= GetIndustrySpec(type
)->behaviour
;
1475 for (const IndustryTileLayoutTile
&it
: layout
) {
1476 IndustryGfx gfx
= GetTranslatedIndustryTileID(it
.gfx
);
1477 TileIndex cur_tile
= TileAddWrap(tile
, it
.ti
.x
, it
.ti
.y
);
1479 if (!IsValidTile(cur_tile
)) {
1480 return_cmd_error(STR_ERROR_SITE_UNSUITABLE
);
1483 if (gfx
== GFX_WATERTILE_SPECIALCHECK
) {
1484 if (!IsWaterTile(cur_tile
) ||
1485 !IsTileFlat(cur_tile
)) {
1486 return_cmd_error(STR_ERROR_SITE_UNSUITABLE
);
1489 CommandCost ret
= EnsureNoVehicleOnGround(cur_tile
);
1490 if (ret
.Failed()) return ret
;
1491 if (IsBridgeAbove(cur_tile
)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE
);
1493 const IndustryTileSpec
*its
= GetIndustryTileSpec(gfx
);
1495 /* Perform land/water check if not disabled */
1496 if (!HasBit(its
->slopes_refused
, 5) && ((HasTileWaterClass(cur_tile
) && IsTileOnWater(cur_tile
)) == !(ind_behav
& INDUSTRYBEH_BUILT_ONWATER
))) return_cmd_error(STR_ERROR_SITE_UNSUITABLE
);
1498 if ((ind_behav
& (INDUSTRYBEH_ONLY_INTOWN
| INDUSTRYBEH_TOWN1200_MORE
)) || // Tile must be a house
1499 ((ind_behav
& INDUSTRYBEH_ONLY_NEARTOWN
) && IsTileType(cur_tile
, MP_HOUSE
))) { // Tile is allowed to be a house (and it is a house)
1500 if (!IsTileType(cur_tile
, MP_HOUSE
)) {
1501 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS
);
1504 /* Clear the tiles as OWNER_TOWN to not affect town rating, and to not clear protected buildings */
1505 Backup
<CompanyID
> cur_company(_current_company
, OWNER_TOWN
);
1506 ret
= Command
<CMD_LANDSCAPE_CLEAR
>::Do(DC_NONE
, cur_tile
);
1507 cur_company
.Restore();
1509 if (ret
.Failed()) return ret
;
1511 /* Clear the tiles, but do not affect town ratings */
1512 ret
= Command
<CMD_LANDSCAPE_CLEAR
>::Do(DC_AUTO
| DC_NO_TEST_TOWN_RATING
| DC_NO_MODIFY_TOWN_RATING
, cur_tile
);
1513 if (ret
.Failed()) return ret
;
1518 return CommandCost();
1522 * Check slope requirements for industry tiles.
1523 * @param tile Position to check.
1524 * @param layout Industry tiles table.
1525 * @param layout_index The index of the layout to build/fund
1526 * @param type Type of the industry.
1527 * @param initial_random_bits The random bits the industry is going to have after construction.
1528 * @param founder Industry founder
1529 * @param creation_type The circumstances the industry is created under.
1530 * @param[out] custom_shape_check Perform custom check for the site.
1531 * @return Failed or succeeded command.
1533 static CommandCost
CheckIfIndustryTileSlopes(TileIndex tile
, const IndustryTileLayout
&layout
, size_t layout_index
, int type
, uint16_t initial_random_bits
, Owner founder
, IndustryAvailabilityCallType creation_type
, bool *custom_shape_check
= nullptr)
1535 bool refused_slope
= false;
1536 bool custom_shape
= false;
1538 for (const IndustryTileLayoutTile
&it
: layout
) {
1539 IndustryGfx gfx
= GetTranslatedIndustryTileID(it
.gfx
);
1540 TileIndex cur_tile
= TileAddWrap(tile
, it
.ti
.x
, it
.ti
.y
);
1541 assert(IsValidTile(cur_tile
)); // checked before in CheckIfIndustryTilesAreFree
1543 if (gfx
!= GFX_WATERTILE_SPECIALCHECK
) {
1544 const IndustryTileSpec
*its
= GetIndustryTileSpec(gfx
);
1546 if (HasBit(its
->callback_mask
, CBM_INDT_SHAPE_CHECK
)) {
1547 custom_shape
= true;
1548 CommandCost ret
= PerformIndustryTileSlopeCheck(tile
, cur_tile
, its
, type
, gfx
, layout_index
, initial_random_bits
, founder
, creation_type
);
1549 if (ret
.Failed()) return ret
;
1551 Slope tileh
= GetTileSlope(cur_tile
);
1552 refused_slope
|= IsSlopeRefused(tileh
, its
->slopes_refused
);
1557 if (custom_shape_check
!= nullptr) *custom_shape_check
= custom_shape
;
1559 /* It is almost impossible to have a fully flat land in TG, so what we
1560 * do is that we check if we can make the land flat later on. See
1561 * CheckIfCanLevelIndustryPlatform(). */
1562 if (!refused_slope
|| (_settings_game
.game_creation
.land_generator
== LG_TERRAGENESIS
&& _generating_world
&& !custom_shape
&& !_ignore_restrictions
)) {
1563 return CommandCost();
1565 return_cmd_error(STR_ERROR_SITE_UNSUITABLE
);
1569 * Is the industry allowed to be built at this place for the town?
1570 * @param tile Tile to construct the industry.
1571 * @param type Type of the industry.
1572 * @param t Town authority that the industry belongs to.
1573 * @return Succeeded or failed command.
1575 static CommandCost
CheckIfIndustryIsAllowed(TileIndex tile
, int type
, const Town
*t
)
1577 if ((GetIndustrySpec(type
)->behaviour
& INDUSTRYBEH_TOWN1200_MORE
) && t
->cache
.population
< 1200) {
1578 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200
);
1581 if ((GetIndustrySpec(type
)->behaviour
& INDUSTRYBEH_ONLY_NEARTOWN
) && DistanceMax(t
->xy
, tile
) > 9) {
1582 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER
);
1585 return CommandCost();
1588 static bool CheckCanTerraformSurroundingTiles(TileIndex tile
, uint height
, int internal
)
1590 /* Check if we don't leave the map */
1591 if (TileX(tile
) == 0 || TileY(tile
) == 0 || GetTileType(tile
) == MP_VOID
) return false;
1593 TileArea
ta(tile
- TileDiffXY(1, 1), 2, 2);
1594 for (TileIndex tile_walk
: ta
) {
1595 uint curh
= TileHeight(tile_walk
);
1596 /* Is the tile clear? */
1597 if ((GetTileType(tile_walk
) != MP_CLEAR
) && (GetTileType(tile_walk
) != MP_TREES
)) return false;
1599 /* Don't allow too big of a change if this is the sub-tile check */
1600 if (internal
!= 0 && Delta(curh
, height
) > 1) return false;
1602 /* Different height, so the surrounding tiles of this tile
1603 * has to be correct too (in level, or almost in level)
1604 * else you get a chain-reaction of terraforming. */
1605 if (internal
== 0 && curh
!= height
) {
1606 if (TileX(tile_walk
) == 0 || TileY(tile_walk
) == 0 || !CheckCanTerraformSurroundingTiles(tile_walk
+ TileDiffXY(-1, -1), height
, internal
+ 1)) {
1616 * This function tries to flatten out the land below an industry, without
1617 * damaging the surroundings too much.
1619 static bool CheckIfCanLevelIndustryPlatform(TileIndex tile
, DoCommandFlag flags
, const IndustryTileLayout
&layout
)
1624 /* Finds dimensions of largest variant of this industry */
1625 for (const IndustryTileLayoutTile
&it
: layout
) {
1626 if (it
.gfx
== GFX_WATERTILE_SPECIALCHECK
) continue; // watercheck tiles don't count for footprint size
1627 if (it
.ti
.x
> max_x
) max_x
= it
.ti
.x
;
1628 if (it
.ti
.y
> max_y
) max_y
= it
.ti
.y
;
1631 /* Remember level height */
1632 uint h
= TileHeight(tile
);
1634 if (TileX(tile
) <= _settings_game
.construction
.industry_platform
+ 1U || TileY(tile
) <= _settings_game
.construction
.industry_platform
+ 1U) return false;
1635 /* Check that all tiles in area and surrounding are clear
1636 * this determines that there are no obstructing items */
1638 /* TileArea::Expand is not used here as we need to abort
1639 * instead of clamping if the bounds cannot expanded. */
1640 TileArea
ta(tile
+ TileDiffXY(-_settings_game
.construction
.industry_platform
, -_settings_game
.construction
.industry_platform
),
1641 max_x
+ 2 + 2 * _settings_game
.construction
.industry_platform
, max_y
+ 2 + 2 * _settings_game
.construction
.industry_platform
);
1643 if (TileX(ta
.tile
) + ta
.w
>= Map::MaxX() || TileY(ta
.tile
) + ta
.h
>= Map::MaxY()) return false;
1645 /* _current_company is OWNER_NONE for randomly generated industries and in editor, or the company who funded or prospected the industry.
1646 * Perform terraforming as OWNER_TOWN to disable autoslope and town ratings. */
1647 Backup
<CompanyID
> cur_company(_current_company
, OWNER_TOWN
);
1649 for (TileIndex tile_walk
: ta
) {
1650 uint curh
= TileHeight(tile_walk
);
1652 /* This tile needs terraforming. Check if we can do that without
1653 * damaging the surroundings too much. */
1654 if (!CheckCanTerraformSurroundingTiles(tile_walk
, h
, 0)) {
1655 cur_company
.Restore();
1658 /* This is not 100% correct check, but the best we can do without modifying the map.
1659 * What is missing, is if the difference in height is more than 1.. */
1660 if (std::get
<0>(Command
<CMD_TERRAFORM_LAND
>::Do(flags
& ~DC_EXEC
, tile_walk
, SLOPE_N
, curh
<= h
)).Failed()) {
1661 cur_company
.Restore();
1667 if (flags
& DC_EXEC
) {
1668 /* Terraform the land under the industry */
1669 for (TileIndex tile_walk
: ta
) {
1670 uint curh
= TileHeight(tile_walk
);
1672 /* We give the terraforming for free here, because we can't calculate
1673 * exact cost in the test-round, and as we all know, that will cause
1674 * a nice assert if they don't match ;) */
1675 Command
<CMD_TERRAFORM_LAND
>::Do(flags
, tile_walk
, SLOPE_N
, curh
<= h
);
1676 curh
+= (curh
> h
) ? -1 : 1;
1681 cur_company
.Restore();
1687 * Check that the new industry is far enough from conflicting industries.
1688 * @param tile Tile to construct the industry.
1689 * @param type Type of the new industry.
1690 * @return Succeeded or failed command.
1692 static CommandCost
CheckIfFarEnoughFromConflictingIndustry(TileIndex tile
, int type
)
1694 const IndustrySpec
*indspec
= GetIndustrySpec(type
);
1696 /* On a large map with many industries, it may be faster to check an area. */
1697 static const int dmax
= 14;
1698 if (Industry::GetNumItems() > static_cast<size_t>(dmax
* dmax
* 2)) {
1699 const Industry
*i
= nullptr;
1700 TileArea tile_area
= TileArea(tile
, 1, 1).Expand(dmax
);
1701 for (TileIndex atile
: tile_area
) {
1702 if (GetTileType(atile
) == MP_INDUSTRY
) {
1703 const Industry
*i2
= Industry::GetByTile(atile
);
1704 if (i
== i2
) continue;
1706 if (DistanceMax(tile
, i
->location
.tile
) > (uint
)dmax
) continue;
1707 if (i
->type
== indspec
->conflicting
[0] ||
1708 i
->type
== indspec
->conflicting
[1] ||
1709 i
->type
== indspec
->conflicting
[2]) {
1710 return_cmd_error(STR_ERROR_INDUSTRY_TOO_CLOSE
);
1714 return CommandCost();
1717 for (const Industry
*i
: Industry::Iterate()) {
1718 /* Within 14 tiles from another industry is considered close */
1719 if (DistanceMax(tile
, i
->location
.tile
) > 14) continue;
1721 /* check if there are any conflicting industry types around */
1722 if (i
->type
== indspec
->conflicting
[0] ||
1723 i
->type
== indspec
->conflicting
[1] ||
1724 i
->type
== indspec
->conflicting
[2]) {
1725 return_cmd_error(STR_ERROR_INDUSTRY_TOO_CLOSE
);
1728 return CommandCost();
1732 * Advertise about a new industry opening.
1733 * @param ind Industry being opened.
1735 static void AdvertiseIndustryOpening(const Industry
*ind
)
1737 const IndustrySpec
*ind_spc
= GetIndustrySpec(ind
->type
);
1738 SetDParam(0, ind_spc
->name
);
1739 if (ind_spc
->new_industry_text
> STR_LAST_STRINGID
) {
1740 SetDParam(1, STR_TOWN_NAME
);
1741 SetDParam(2, ind
->town
->index
);
1743 SetDParam(1, ind
->town
->index
);
1745 AddIndustryNewsItem(ind_spc
->new_industry_text
, NT_INDUSTRY_OPEN
, ind
->index
);
1746 AI::BroadcastNewEvent(new ScriptEventIndustryOpen(ind
->index
));
1747 Game::NewEvent(new ScriptEventIndustryOpen(ind
->index
));
1751 * Populate an industry's list of nearby stations, and if it accepts any cargo, also
1752 * add the industry to each station's nearby industry list.
1753 * @param ind Industry
1755 static void PopulateStationsNearby(Industry
*ind
)
1757 if (ind
->neutral_station
!= nullptr && !_settings_game
.station
.serve_neutral_industries
) {
1758 /* Industry has a neutral station. Use it and ignore any other nearby stations. */
1759 ind
->stations_near
.insert(ind
->neutral_station
);
1760 ind
->neutral_station
->industries_near
.clear();
1761 ind
->neutral_station
->industries_near
.insert(IndustryListEntry
{0, ind
});
1765 ForAllStationsAroundTiles(ind
->location
, [ind
](Station
*st
, TileIndex tile
) {
1766 if (!IsTileType(tile
, MP_INDUSTRY
) || GetIndustryIndex(tile
) != ind
->index
) return false;
1767 ind
->stations_near
.insert(st
);
1768 st
->AddIndustryToDeliver(ind
, tile
);
1774 * Put an industry on the map.
1775 * @param i Just allocated poolitem, mostly empty.
1776 * @param tile North tile of the industry.
1777 * @param type Type of the industry.
1778 * @param layout Industrylayout to build.
1779 * @param layout_index Number of the industry layout.
1780 * @param t Nearest town.
1781 * @param founder Founder of the industry; OWNER_NONE in case of random construction.
1782 * @param initial_random_bits Random bits for the industry.
1784 static void DoCreateNewIndustry(Industry
*i
, TileIndex tile
, IndustryType type
, const IndustryTileLayout
&layout
, size_t layout_index
, Town
*t
, Owner founder
, uint16_t initial_random_bits
)
1786 const IndustrySpec
*indspec
= GetIndustrySpec(type
);
1788 i
->location
= TileArea(tile
, 1, 1);
1790 Industry::IncIndustryTypeCount(type
);
1792 for (size_t index
= 0; index
< std::size(indspec
->produced_cargo
); ++index
) {
1793 if (!IsValidCargoID(indspec
->produced_cargo
[index
])) break;
1795 Industry::ProducedCargo
&p
= i
->produced
.emplace_back();
1796 p
.cargo
= indspec
->produced_cargo
[index
];
1797 p
.rate
= indspec
->production_rate
[index
];
1800 for (size_t index
= 0; index
< std::size(indspec
->accepts_cargo
); ++index
) {
1801 if (!IsValidCargoID(indspec
->accepts_cargo
[index
])) break;
1803 Industry::AcceptedCargo
&a
= i
->accepted
.emplace_back();
1804 a
.cargo
= indspec
->accepts_cargo
[index
];
1807 /* Randomize inital production if non-original economy is used and there are no production related callbacks. */
1808 if (!indspec
->UsesOriginalEconomy()) {
1809 for (auto &p
: i
->produced
) {
1810 p
.rate
= ClampTo
<uint8_t>((RandomRange(256) + 128) * p
.rate
>> 8);
1815 i
->owner
= OWNER_NONE
;
1817 uint16_t r
= Random();
1818 i
->random_colour
= static_cast<Colours
>(GB(r
, 0, 4));
1819 i
->counter
= GB(r
, 4, 12);
1820 i
->random
= initial_random_bits
;
1821 i
->was_cargo_delivered
= false;
1822 i
->last_prod_year
= TimerGameEconomy::year
;
1823 i
->founder
= founder
;
1824 i
->ctlflags
= INDCTL_NONE
;
1826 i
->construction_date
= TimerGameCalendar::date
;
1827 i
->construction_type
= (_game_mode
== GM_EDITOR
) ? ICT_SCENARIO_EDITOR
:
1828 (_generating_world
? ICT_MAP_GENERATION
: ICT_NORMAL_GAMEPLAY
);
1830 /* Adding 1 here makes it conform to specs of var44 of varaction2 for industries
1831 * 0 = created prior of newindustries
1832 * else, chosen layout + 1 */
1833 i
->selected_layout
= (uint8_t)(layout_index
+ 1);
1835 i
->exclusive_supplier
= INVALID_OWNER
;
1836 i
->exclusive_consumer
= INVALID_OWNER
;
1838 i
->prod_level
= PRODLEVEL_DEFAULT
;
1840 /* Call callbacks after the regular fields got initialised. */
1842 if (HasBit(indspec
->callback_mask
, CBM_IND_PROD_CHANGE_BUILD
)) {
1843 uint16_t res
= GetIndustryCallback(CBID_INDUSTRY_PROD_CHANGE_BUILD
, 0, Random(), i
, type
, INVALID_TILE
);
1844 if (res
!= CALLBACK_FAILED
) {
1845 if (res
< PRODLEVEL_MINIMUM
|| res
> PRODLEVEL_MAXIMUM
) {
1846 ErrorUnknownCallbackResult(indspec
->grf_prop
.grffile
->grfid
, CBID_INDUSTRY_PROD_CHANGE_BUILD
, res
);
1848 i
->prod_level
= res
;
1849 i
->RecomputeProductionMultipliers();
1854 if (_generating_world
) {
1855 if (HasBit(indspec
->callback_mask
, CBM_IND_PRODUCTION_256_TICKS
)) {
1856 IndustryProductionCallback(i
, 1);
1857 for (auto &p
: i
->produced
) {
1858 p
.history
[LAST_MONTH
].production
= p
.waiting
* 8;
1863 for (auto &p
: i
->produced
) {
1864 p
.history
[LAST_MONTH
].production
+= ScaleByCargoScale(p
.rate
* 8, false);
1868 if (HasBit(indspec
->callback_mask
, CBM_IND_DECIDE_COLOUR
)) {
1869 uint16_t res
= GetIndustryCallback(CBID_INDUSTRY_DECIDE_COLOUR
, 0, 0, i
, type
, INVALID_TILE
);
1870 if (res
!= CALLBACK_FAILED
) {
1871 if (GB(res
, 4, 11) != 0) ErrorUnknownCallbackResult(indspec
->grf_prop
.grffile
->grfid
, CBID_INDUSTRY_DECIDE_COLOUR
, res
);
1872 i
->random_colour
= static_cast<Colours
>(GB(res
, 0, 4));
1876 if (HasBit(indspec
->callback_mask
, CBM_IND_INPUT_CARGO_TYPES
)) {
1877 /* Clear all input cargo types */
1878 i
->accepted
.clear();
1879 /* Query actual types */
1880 uint maxcargoes
= (indspec
->behaviour
& INDUSTRYBEH_CARGOTYPES_UNLIMITED
) ? INDUSTRY_NUM_INPUTS
: 3;
1881 for (uint j
= 0; j
< maxcargoes
; j
++) {
1882 uint16_t res
= GetIndustryCallback(CBID_INDUSTRY_INPUT_CARGO_TYPES
, j
, 0, i
, type
, INVALID_TILE
);
1883 if (res
== CALLBACK_FAILED
|| GB(res
, 0, 8) == UINT8_MAX
) break;
1884 if (indspec
->grf_prop
.grffile
->grf_version
>= 8 && res
>= 0x100) {
1885 ErrorUnknownCallbackResult(indspec
->grf_prop
.grffile
->grfid
, CBID_INDUSTRY_INPUT_CARGO_TYPES
, res
);
1888 CargoID cargo
= GetCargoTranslation(GB(res
, 0, 8), indspec
->grf_prop
.grffile
);
1889 /* Industries without "unlimited" cargo types support depend on the specific order/slots of cargo types.
1890 * They need to be able to blank out specific slots without aborting the callback sequence,
1891 * and solve this by returning undefined cargo indexes. Skip these. */
1892 if (!IsValidCargoID(cargo
) && !(indspec
->behaviour
& INDUSTRYBEH_CARGOTYPES_UNLIMITED
)) {
1893 /* As slots are allocated as needed now, this means we do need to add a slot for the invalid cargo. */
1894 Industry::AcceptedCargo
&a
= i
->accepted
.emplace_back();
1895 a
.cargo
= INVALID_CARGO
;
1898 /* Verify valid cargo */
1899 if (std::find(std::begin(indspec
->accepts_cargo
), std::end(indspec
->accepts_cargo
), cargo
) == std::end(indspec
->accepts_cargo
)) {
1900 /* Cargo not in spec, error in NewGRF */
1901 ErrorUnknownCallbackResult(indspec
->grf_prop
.grffile
->grfid
, CBID_INDUSTRY_INPUT_CARGO_TYPES
, res
);
1904 if (std::any_of(std::begin(i
->accepted
), std::begin(i
->accepted
) + j
, [&cargo
](const auto &a
) { return a
.cargo
== cargo
; })) {
1905 /* Duplicate cargo */
1906 ErrorUnknownCallbackResult(indspec
->grf_prop
.grffile
->grfid
, CBID_INDUSTRY_INPUT_CARGO_TYPES
, res
);
1909 Industry::AcceptedCargo
&a
= i
->accepted
.emplace_back();
1914 if (HasBit(indspec
->callback_mask
, CBM_IND_OUTPUT_CARGO_TYPES
)) {
1915 /* Clear all output cargo types */
1916 i
->produced
.clear();
1917 /* Query actual types */
1918 uint maxcargoes
= (indspec
->behaviour
& INDUSTRYBEH_CARGOTYPES_UNLIMITED
) ? INDUSTRY_NUM_OUTPUTS
: 2;
1919 for (uint j
= 0; j
< maxcargoes
; j
++) {
1920 uint16_t res
= GetIndustryCallback(CBID_INDUSTRY_OUTPUT_CARGO_TYPES
, j
, 0, i
, type
, INVALID_TILE
);
1921 if (res
== CALLBACK_FAILED
|| GB(res
, 0, 8) == UINT8_MAX
) break;
1922 if (indspec
->grf_prop
.grffile
->grf_version
>= 8 && res
>= 0x100) {
1923 ErrorUnknownCallbackResult(indspec
->grf_prop
.grffile
->grfid
, CBID_INDUSTRY_OUTPUT_CARGO_TYPES
, res
);
1926 CargoID cargo
= GetCargoTranslation(GB(res
, 0, 8), indspec
->grf_prop
.grffile
);
1927 /* Allow older GRFs to skip slots. */
1928 if (!IsValidCargoID(cargo
) && !(indspec
->behaviour
& INDUSTRYBEH_CARGOTYPES_UNLIMITED
)) {
1929 /* As slots are allocated as needed now, this means we do need to add a slot for the invalid cargo. */
1930 Industry::ProducedCargo
&p
= i
->produced
.emplace_back();
1931 p
.cargo
= INVALID_CARGO
;
1934 /* Verify valid cargo */
1935 if (std::find(std::begin(indspec
->produced_cargo
), std::end(indspec
->produced_cargo
), cargo
) == std::end(indspec
->produced_cargo
)) {
1936 /* Cargo not in spec, error in NewGRF */
1937 ErrorUnknownCallbackResult(indspec
->grf_prop
.grffile
->grfid
, CBID_INDUSTRY_OUTPUT_CARGO_TYPES
, res
);
1940 if (std::any_of(std::begin(i
->produced
), std::begin(i
->produced
) + j
, [&cargo
](const auto &p
) { return p
.cargo
== cargo
; })) {
1941 /* Duplicate cargo */
1942 ErrorUnknownCallbackResult(indspec
->grf_prop
.grffile
->grfid
, CBID_INDUSTRY_OUTPUT_CARGO_TYPES
, res
);
1945 Industry::ProducedCargo
&p
= i
->produced
.emplace_back();
1950 /* Plant the tiles */
1952 for (const IndustryTileLayoutTile
&it
: layout
) {
1953 TileIndex cur_tile
= tile
+ ToTileIndexDiff(it
.ti
);
1955 if (it
.gfx
!= GFX_WATERTILE_SPECIALCHECK
) {
1956 i
->location
.Add(cur_tile
);
1958 WaterClass wc
= (IsWaterTile(cur_tile
) ? GetWaterClass(cur_tile
) : WATER_CLASS_INVALID
);
1960 Command
<CMD_LANDSCAPE_CLEAR
>::Do(DC_EXEC
| DC_NO_TEST_TOWN_RATING
| DC_NO_MODIFY_TOWN_RATING
, cur_tile
);
1962 MakeIndustry(cur_tile
, i
->index
, it
.gfx
, Random(), wc
);
1964 if (_generating_world
) {
1965 SetIndustryConstructionCounter(cur_tile
, 3);
1966 SetIndustryConstructionStage(cur_tile
, 2);
1969 /* it->gfx is stored in the map. But the translated ID cur_gfx is the interesting one */
1970 IndustryGfx cur_gfx
= GetTranslatedIndustryTileID(it
.gfx
);
1971 const IndustryTileSpec
*its
= GetIndustryTileSpec(cur_gfx
);
1972 if (its
->animation
.status
!= ANIM_STATUS_NO_ANIMATION
) AddAnimatedTile(cur_tile
);
1976 if (GetIndustrySpec(i
->type
)->behaviour
& INDUSTRYBEH_PLANT_ON_BUILT
) {
1977 for (uint j
= 0; j
!= 50; j
++) PlantRandomFarmField(i
);
1979 InvalidateWindowData(WC_INDUSTRY_DIRECTORY
, 0, IDIWD_FORCE_REBUILD
);
1980 SetWindowDirty(WC_BUILD_INDUSTRY
, 0);
1982 if (!_generating_world
) PopulateStationsNearby(i
);
1986 * Helper function for Build/Fund an industry
1987 * @param tile tile where industry is built
1988 * @param type of industry to build
1989 * @param flags of operations to conduct
1990 * @param indspec pointer to industry specifications
1991 * @param layout_index the index of the itsepc to build/fund
1992 * @param random_var8f random seed (possibly) used by industries
1993 * @param random_initial_bits The random bits the industry is going to have after construction.
1994 * @param founder Founder of the industry
1995 * @param creation_type The circumstances the industry is created under.
1996 * @param[out] ip Pointer to store newly created industry.
1997 * @return Succeeded or failed command.
1999 * @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.
2001 static CommandCost
CreateNewIndustryHelper(TileIndex tile
, IndustryType type
, DoCommandFlag flags
, const IndustrySpec
*indspec
, size_t layout_index
, uint32_t random_var8f
, uint16_t random_initial_bits
, Owner founder
, IndustryAvailabilityCallType creation_type
, Industry
**ip
)
2003 assert(layout_index
< indspec
->layouts
.size());
2004 const IndustryTileLayout
&layout
= indspec
->layouts
[layout_index
];
2008 /* 1. Cheap: Built-in checks on industry level. */
2009 CommandCost ret
= CheckIfFarEnoughFromConflictingIndustry(tile
, type
);
2010 if (ret
.Failed()) return ret
;
2013 ret
= FindTownForIndustry(tile
, type
, &t
);
2014 if (ret
.Failed()) return ret
;
2015 assert(t
!= nullptr);
2017 ret
= CheckIfIndustryIsAllowed(tile
, type
, t
);
2018 if (ret
.Failed()) return ret
;
2020 /* 2. Built-in checks on industry tiles. */
2021 std::vector
<ClearedObjectArea
> object_areas(_cleared_object_areas
);
2022 ret
= CheckIfIndustryTilesAreFree(tile
, layout
, type
);
2023 _cleared_object_areas
= object_areas
;
2024 if (ret
.Failed()) return ret
;
2026 /* 3. NewGRF-defined checks on industry level. */
2027 if (HasBit(GetIndustrySpec(type
)->callback_mask
, CBM_IND_LOCATION
)) {
2028 ret
= CheckIfCallBackAllowsCreation(tile
, type
, layout_index
, random_var8f
, random_initial_bits
, founder
, creation_type
);
2030 ret
= _check_new_industry_procs
[indspec
->check_proc
](tile
);
2032 if (ret
.Failed()) return ret
;
2034 /* 4. Expensive: NewGRF-defined checks on industry tiles. */
2035 bool custom_shape_check
= false;
2036 ret
= CheckIfIndustryTileSlopes(tile
, layout
, layout_index
, type
, random_initial_bits
, founder
, creation_type
, &custom_shape_check
);
2037 if (ret
.Failed()) return ret
;
2039 if (!custom_shape_check
&& _settings_game
.game_creation
.land_generator
== LG_TERRAGENESIS
&& _generating_world
&&
2040 !_ignore_restrictions
&& !CheckIfCanLevelIndustryPlatform(tile
, DC_NO_WATER
, layout
)) {
2041 return_cmd_error(STR_ERROR_SITE_UNSUITABLE
);
2044 if (!Industry::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_INDUSTRIES
);
2046 if (flags
& DC_EXEC
) {
2047 *ip
= new Industry(tile
);
2048 if (!custom_shape_check
) CheckIfCanLevelIndustryPlatform(tile
, DC_NO_WATER
| DC_EXEC
, layout
);
2049 DoCreateNewIndustry(*ip
, tile
, type
, layout
, layout_index
, t
, founder
, random_initial_bits
);
2052 return CommandCost();
2056 * Build/Fund an industry
2057 * @param flags of operations to conduct
2058 * @param tile tile where industry is built
2059 * @param it industry type see build_industry.h and see industry.h
2060 * @param first_layout first layout to try
2061 * @param fund false = prospect, true = fund (only valid if current company is DEITY)
2062 * @param seed seed to use for desyncfree randomisations
2063 * @return the cost of this operation or an error
2065 CommandCost
CmdBuildIndustry(DoCommandFlag flags
, TileIndex tile
, IndustryType it
, uint32_t first_layout
, bool fund
, uint32_t seed
)
2067 if (it
>= NUM_INDUSTRYTYPES
) return CMD_ERROR
;
2069 const IndustrySpec
*indspec
= GetIndustrySpec(it
);
2071 /* Check if the to-be built/founded industry is available for this climate. */
2072 if (!indspec
->enabled
|| indspec
->layouts
.empty()) return CMD_ERROR
;
2074 /* If the setting for raw-material industries is not on, you cannot build raw-material industries.
2075 * Raw material industries are industries that do not accept cargo (at least for now) */
2076 if (_game_mode
!= GM_EDITOR
&& _current_company
!= OWNER_DEITY
&& _settings_game
.construction
.raw_industry_construction
== 0 && indspec
->IsRawIndustry()) {
2080 if (_game_mode
!= GM_EDITOR
&& GetIndustryProbabilityCallback(it
, _current_company
== OWNER_DEITY
? IACT_RANDOMCREATION
: IACT_USERCREATION
, 1) == 0) {
2084 Randomizer randomizer
;
2085 randomizer
.SetSeed(seed
);
2086 uint16_t random_initial_bits
= GB(seed
, 0, 16);
2087 uint32_t random_var8f
= randomizer
.Next();
2088 size_t num_layouts
= indspec
->layouts
.size();
2089 CommandCost ret
= CommandCost(STR_ERROR_SITE_UNSUITABLE
);
2090 const bool deity_prospect
= _current_company
== OWNER_DEITY
&& !fund
;
2092 Industry
*ind
= nullptr;
2093 if (deity_prospect
|| (_game_mode
!= GM_EDITOR
&& _current_company
!= OWNER_DEITY
&& _settings_game
.construction
.raw_industry_construction
== 2 && indspec
->IsRawIndustry())) {
2094 if (flags
& DC_EXEC
) {
2095 /* Prospecting has a chance to fail, however we cannot guarantee that something can
2096 * be built on the map, so the chance gets lower when the map is fuller, but there
2097 * is nothing we can really do about that. */
2098 bool prospect_success
= deity_prospect
|| Random() <= indspec
->prospecting_chance
;
2099 if (prospect_success
) {
2100 /* Prospected industries are build as OWNER_TOWN to not e.g. be build on owned land of the founder */
2101 IndustryAvailabilityCallType calltype
= _current_company
== OWNER_DEITY
? IACT_RANDOMCREATION
: IACT_PROSPECTCREATION
;
2102 Backup
<CompanyID
> cur_company(_current_company
, OWNER_TOWN
);
2103 for (int i
= 0; i
< 5000; i
++) {
2104 /* We should not have more than one Random() in a function call
2105 * because parameter evaluation order is not guaranteed in the c++ standard
2107 tile
= RandomTile();
2108 /* Start with a random layout */
2109 size_t layout
= RandomRange((uint32_t)num_layouts
);
2110 /* Check now each layout, starting with the random one */
2111 for (size_t j
= 0; j
< num_layouts
; j
++) {
2112 layout
= (layout
+ 1) % num_layouts
;
2113 ret
= CreateNewIndustryHelper(tile
, it
, flags
, indspec
, layout
, random_var8f
, random_initial_bits
, cur_company
.GetOriginalValue(), calltype
, &ind
);
2114 if (ret
.Succeeded()) break;
2116 if (ret
.Succeeded()) break;
2118 cur_company
.Restore();
2120 if (ret
.Failed() && IsLocalCompany()) {
2121 if (prospect_success
) {
2122 ShowErrorMessage(STR_ERROR_CAN_T_PROSPECT_INDUSTRY
, STR_ERROR_NO_SUITABLE_PLACES_FOR_PROSPECTING
, WL_INFO
);
2124 ShowErrorMessage(STR_ERROR_CAN_T_PROSPECT_INDUSTRY
, STR_ERROR_PROSPECTING_WAS_UNLUCKY
, WL_INFO
);
2129 size_t layout
= first_layout
;
2130 if (layout
>= num_layouts
) return CMD_ERROR
;
2132 /* Check subsequently each layout, starting with the given layout in p1 */
2133 for (size_t i
= 0; i
< num_layouts
; i
++) {
2134 layout
= (layout
+ 1) % num_layouts
;
2135 ret
= CreateNewIndustryHelper(tile
, it
, flags
, indspec
, layout
, random_var8f
, random_initial_bits
, _current_company
, _current_company
== OWNER_DEITY
? IACT_RANDOMCREATION
: IACT_USERCREATION
, &ind
);
2136 if (ret
.Succeeded()) break;
2139 /* If it still failed, there's no suitable layout to build here, return the error */
2140 if (ret
.Failed()) return ret
;
2143 if ((flags
& DC_EXEC
) && ind
!= nullptr && _game_mode
!= GM_EDITOR
) {
2144 AdvertiseIndustryOpening(ind
);
2147 return CommandCost(EXPENSES_OTHER
, indspec
->GetConstructionCost());
2151 * Set industry control flags.
2152 * @param flags Type of operation.
2153 * @param ind_id IndustryID
2154 * @param ctlflags IndustryControlFlags
2155 * @return Empty cost or an error.
2157 CommandCost
CmdIndustrySetFlags(DoCommandFlag flags
, IndustryID ind_id
, IndustryControlFlags ctlflags
)
2159 if (_current_company
!= OWNER_DEITY
) return CMD_ERROR
;
2161 Industry
*ind
= Industry::GetIfValid(ind_id
);
2162 if (ind
== nullptr) return CMD_ERROR
;
2164 if (flags
& DC_EXEC
) ind
->ctlflags
= ctlflags
& INDCTL_MASK
;
2166 return CommandCost();
2170 * Set industry production.
2171 * @param flags Type of operation.
2172 * @param ind_id IndustryID
2173 * @param prod_level Production level.
2174 * @param show_news Show a news message on production change.
2175 * @param custom_news Custom news message text.
2176 * @return Empty cost or an error.
2178 CommandCost
CmdIndustrySetProduction(DoCommandFlag flags
, IndustryID ind_id
, uint8_t prod_level
, bool show_news
, const std::string
&custom_news
)
2180 if (_current_company
!= OWNER_DEITY
) return CMD_ERROR
;
2181 if (prod_level
< PRODLEVEL_MINIMUM
|| prod_level
> PRODLEVEL_MAXIMUM
) return CMD_ERROR
;
2183 Industry
*ind
= Industry::GetIfValid(ind_id
);
2184 if (ind
== nullptr) return CMD_ERROR
;
2186 if (flags
& DC_EXEC
) {
2187 StringID str
= STR_NULL
;
2188 if (prod_level
> ind
->prod_level
) {
2189 str
= GetIndustrySpec(ind
->type
)->production_up_text
;
2190 } else if (prod_level
< ind
->prod_level
) {
2191 str
= GetIndustrySpec(ind
->type
)->production_down_text
;
2193 if (prod_level
!= ind
->prod_level
&& !custom_news
.empty()) str
= STR_NEWS_CUSTOM_ITEM
;
2195 ind
->ctlflags
|= INDCTL_EXTERNAL_PROD_LEVEL
;
2196 ind
->prod_level
= prod_level
;
2197 ind
->RecomputeProductionMultipliers();
2199 /* Show news message if requested. */
2200 if (show_news
&& str
!= STR_NULL
) {
2202 switch (WhoCanServiceIndustry(ind
)) {
2203 case 0: nt
= NT_INDUSTRY_NOBODY
; break;
2204 case 1: nt
= NT_INDUSTRY_OTHER
; break;
2205 case 2: nt
= NT_INDUSTRY_COMPANY
; break;
2206 default: NOT_REACHED();
2209 /* Set parameters of news string */
2210 if (str
== STR_NEWS_CUSTOM_ITEM
) {
2211 SetDParamStr(0, custom_news
);
2212 } else if (str
> STR_LAST_STRINGID
) {
2213 SetDParam(0, STR_TOWN_NAME
);
2214 SetDParam(1, ind
->town
->index
);
2215 SetDParam(2, GetIndustrySpec(ind
->type
)->name
);
2217 SetDParam(0, ind
->index
);
2219 AddIndustryNewsItem(str
, nt
, ind
->index
);
2223 return CommandCost();
2227 * Change exclusive consumer or supplier for the industry.
2228 * @param flags Type of operation.
2229 * @param ind_id IndustryID
2230 * @param company_id CompanyID to set or INVALID_OWNER (available to everyone) or
2231 * OWNER_NONE (neutral stations only) or OWNER_DEITY (no one)
2232 * @param consumer Set exclusive consumer if true, supplier if false.
2233 * @return Empty cost or an error.
2235 CommandCost
CmdIndustrySetExclusivity(DoCommandFlag flags
, IndustryID ind_id
, Owner company_id
, bool consumer
)
2237 if (_current_company
!= OWNER_DEITY
) return CMD_ERROR
;
2239 Industry
*ind
= Industry::GetIfValid(ind_id
);
2240 if (ind
== nullptr) return CMD_ERROR
;
2242 if (company_id
!= OWNER_NONE
&& company_id
!= INVALID_OWNER
&& company_id
!= OWNER_DEITY
2243 && !Company::IsValidID(company_id
)) return CMD_ERROR
;
2245 if (flags
& DC_EXEC
) {
2247 ind
->exclusive_consumer
= company_id
;
2249 ind
->exclusive_supplier
= company_id
;
2254 return CommandCost();
2258 * Change additional industry text.
2259 * @param flags Type of operation.
2260 * @param ind_id IndustryID
2261 * @param text - Additional industry text.
2262 * @return Empty cost or an error.
2264 CommandCost
CmdIndustrySetText(DoCommandFlag flags
, IndustryID ind_id
, const std::string
&text
)
2266 if (_current_company
!= OWNER_DEITY
) return CMD_ERROR
;
2268 Industry
*ind
= Industry::GetIfValid(ind_id
);
2269 if (ind
== nullptr) return CMD_ERROR
;
2271 if (flags
& DC_EXEC
) {
2273 if (!text
.empty()) ind
->text
= text
;
2274 InvalidateWindowData(WC_INDUSTRY_VIEW
, ind
->index
);
2277 return CommandCost();
2281 * Create a new industry of random layout.
2282 * @param tile The location to build the industry.
2283 * @param type The industry type to build.
2284 * @param creation_type The circumstances the industry is created under.
2285 * @return the created industry or nullptr if it failed.
2287 static Industry
*CreateNewIndustry(TileIndex tile
, IndustryType type
, IndustryAvailabilityCallType creation_type
)
2289 const IndustrySpec
*indspec
= GetIndustrySpec(type
);
2291 uint32_t seed
= Random();
2292 uint32_t seed2
= Random();
2293 Industry
*i
= nullptr;
2294 size_t layout_index
= RandomRange((uint32_t)indspec
->layouts
.size());
2295 [[maybe_unused
]] CommandCost ret
= CreateNewIndustryHelper(tile
, type
, DC_EXEC
, indspec
, layout_index
, seed
, GB(seed2
, 0, 16), OWNER_NONE
, creation_type
, &i
);
2296 assert(i
!= nullptr || ret
.Failed());
2301 * Compute the appearance probability for an industry during map creation.
2302 * @param it Industry type to compute.
2303 * @param[out] force_at_least_one Returns whether at least one instance should be forced on map creation.
2304 * @return Relative probability for the industry to appear.
2306 static uint32_t GetScaledIndustryGenerationProbability(IndustryType it
, bool *force_at_least_one
)
2308 const IndustrySpec
*ind_spc
= GetIndustrySpec(it
);
2309 uint32_t chance
= ind_spc
->appear_creation
[_settings_game
.game_creation
.landscape
];
2310 if (!ind_spc
->enabled
|| ind_spc
->layouts
.empty() ||
2311 (_game_mode
!= GM_EDITOR
&& _settings_game
.difficulty
.industry_density
== ID_FUND_ONLY
) ||
2312 (chance
= GetIndustryProbabilityCallback(it
, IACT_MAPGENERATION
, chance
)) == 0) {
2313 *force_at_least_one
= false;
2316 chance
*= 16; // to increase precision
2317 /* We want industries appearing at coast to appear less often on bigger maps, as length of coast increases slower than map area.
2318 * For simplicity we scale in both cases, though scaling the probabilities of all industries has no effect. */
2319 chance
= (ind_spc
->check_proc
== CHECK_REFINERY
|| ind_spc
->check_proc
== CHECK_OIL_RIG
) ? Map::ScaleBySize1D(chance
) : Map::ScaleBySize(chance
);
2321 *force_at_least_one
= (chance
> 0) && !(ind_spc
->behaviour
& INDUSTRYBEH_NOBUILT_MAPCREATION
) && (_game_mode
!= GM_EDITOR
);
2327 * Compute the probability for constructing a new industry during game play.
2328 * @param it Industry type to compute.
2329 * @param[out] min_number Minimal number of industries that should exist at the map.
2330 * @return Relative probability for the industry to appear.
2332 static uint16_t GetIndustryGamePlayProbability(IndustryType it
, uint8_t *min_number
)
2334 if (_settings_game
.difficulty
.industry_density
== ID_FUND_ONLY
) {
2339 const IndustrySpec
*ind_spc
= GetIndustrySpec(it
);
2340 uint8_t chance
= ind_spc
->appear_ingame
[_settings_game
.game_creation
.landscape
];
2341 if (!ind_spc
->enabled
|| ind_spc
->layouts
.empty() ||
2342 ((ind_spc
->behaviour
& INDUSTRYBEH_BEFORE_1950
) && TimerGameCalendar::year
> 1950) ||
2343 ((ind_spc
->behaviour
& INDUSTRYBEH_AFTER_1960
) && TimerGameCalendar::year
< 1960) ||
2344 (chance
= GetIndustryProbabilityCallback(it
, IACT_RANDOMCREATION
, chance
)) == 0) {
2348 *min_number
= (ind_spc
->behaviour
& INDUSTRYBEH_CANCLOSE_LASTINSTANCE
) ? 1 : 0;
2353 * Get wanted number of industries on the map.
2354 * @return Wanted number of industries at the map.
2356 static uint
GetNumberOfIndustries()
2358 /* Number of industries on a 256x256 map. */
2359 static const uint16_t numof_industry_table
[] = {
2369 assert(lengthof(numof_industry_table
) == ID_END
);
2370 uint difficulty
= (_game_mode
!= GM_EDITOR
) ? _settings_game
.difficulty
.industry_density
: (uint
)ID_VERY_LOW
;
2372 if (difficulty
== ID_CUSTOM
) return std::min
<uint
>(IndustryPool::MAX_SIZE
, _settings_game
.game_creation
.custom_industry_number
);
2374 return std::min
<uint
>(IndustryPool::MAX_SIZE
, Map::ScaleBySize(numof_industry_table
[difficulty
]));
2378 * Try to place the industry in the game.
2379 * Since there is no feedback why placement fails, there is no other option
2380 * than to try a few times before concluding it does not work.
2381 * @param type Industry type of the desired industry.
2382 * @param try_hard Try very hard to find a place. (Used to place at least one industry per type.)
2383 * @return Pointer to created industry, or \c nullptr if creation failed.
2385 static Industry
*PlaceIndustry(IndustryType type
, IndustryAvailabilityCallType creation_type
, bool try_hard
)
2387 uint tries
= try_hard
? 10000u : 2000u;
2388 for (; tries
> 0; tries
--) {
2389 Industry
*ind
= CreateNewIndustry(RandomTile(), type
, creation_type
);
2390 if (ind
!= nullptr) return ind
;
2396 * Try to build a industry on the map.
2397 * @param type IndustryType of the desired industry
2398 * @param try_hard Try very hard to find a place. (Used to place at least one industry per type)
2400 static void PlaceInitialIndustry(IndustryType type
, bool try_hard
)
2402 Backup
<CompanyID
> cur_company(_current_company
, OWNER_NONE
);
2404 IncreaseGeneratingWorldProgress(GWP_INDUSTRY
);
2405 PlaceIndustry(type
, IACT_MAPGENERATION
, try_hard
);
2407 cur_company
.Restore();
2411 * Get total number of industries existing in the game.
2412 * @return Number of industries currently in the game.
2414 static uint
GetCurrentTotalNumberOfIndustries()
2417 for (IndustryType it
= 0; it
< NUM_INDUSTRYTYPES
; it
++) total
+= Industry::GetIndustryTypeCount(it
);
2422 /** Reset the entry. */
2423 void IndustryTypeBuildData::Reset()
2425 this->probability
= 0;
2426 this->min_number
= 0;
2427 this->target_count
= 0;
2429 this->wait_count
= 0;
2432 /** Completely reset the industry build data. */
2433 void IndustryBuildData::Reset()
2435 this->wanted_inds
= GetCurrentTotalNumberOfIndustries() << 16;
2437 for (IndustryType it
= 0; it
< NUM_INDUSTRYTYPES
; it
++) {
2438 this->builddata
[it
].Reset();
2442 /** Monthly update of industry build data. */
2443 void IndustryBuildData::EconomyMonthlyLoop()
2445 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.
2446 if (_settings_game
.difficulty
.industry_density
== ID_FUND_ONLY
) return; // 'no industries' setting.
2448 /* To prevent running out of unused industries for the player to connect,
2449 * add a fraction of new industries each month, but only if the manager can keep up. */
2450 uint max_behind
= 1 + std::min(99u, Map::ScaleBySize(3)); // At most 2 industries for small maps, and 100 at the biggest map (about 6 months industry build attempts).
2451 if (GetCurrentTotalNumberOfIndustries() + max_behind
>= (this->wanted_inds
>> 16)) {
2452 this->wanted_inds
+= Map::ScaleBySize(NEWINDS_PER_MONTH
);
2457 * This function will create random industries during game creation.
2458 * It will scale the amount of industries by mapsize and difficulty level.
2460 void GenerateIndustries()
2462 if (_game_mode
!= GM_EDITOR
&& _settings_game
.difficulty
.industry_density
== ID_FUND_ONLY
) return; // No industries in the game.
2464 uint32_t industry_probs
[NUM_INDUSTRYTYPES
];
2465 bool force_at_least_one
[NUM_INDUSTRYTYPES
];
2466 uint32_t total_prob
= 0;
2467 uint num_forced
= 0;
2469 for (IndustryType it
= 0; it
< NUM_INDUSTRYTYPES
; it
++) {
2470 industry_probs
[it
] = GetScaledIndustryGenerationProbability(it
, force_at_least_one
+ it
);
2471 total_prob
+= industry_probs
[it
];
2472 if (force_at_least_one
[it
]) num_forced
++;
2475 uint total_amount
= GetNumberOfIndustries();
2476 if (total_prob
== 0 || total_amount
< num_forced
) {
2477 /* Only place the forced ones */
2478 total_amount
= num_forced
;
2481 SetGeneratingWorldProgress(GWP_INDUSTRY
, total_amount
);
2483 /* Try to build one industry per type independent of any probabilities */
2484 for (IndustryType it
= 0; it
< NUM_INDUSTRYTYPES
; it
++) {
2485 if (force_at_least_one
[it
]) {
2486 assert(total_amount
> 0);
2488 PlaceInitialIndustry(it
, true);
2492 /* Add the remaining industries according to their probabilities */
2493 for (uint i
= 0; i
< total_amount
; i
++) {
2494 uint32_t r
= RandomRange(total_prob
);
2495 IndustryType it
= 0;
2496 while (r
>= industry_probs
[it
]) {
2497 r
-= industry_probs
[it
];
2499 assert(it
< NUM_INDUSTRYTYPES
);
2501 assert(industry_probs
[it
] > 0);
2502 PlaceInitialIndustry(it
, false);
2504 _industry_builder
.Reset();
2508 * Monthly update of industry statistics.
2509 * @param i Industry to update.
2511 static void UpdateIndustryStatistics(Industry
*i
)
2513 for (auto &p
: i
->produced
) {
2514 if (IsValidCargoID(p
.cargo
)) {
2515 if (p
.history
[THIS_MONTH
].production
!= 0) i
->last_prod_year
= TimerGameEconomy::year
;
2517 /* Move history from this month to last month. */
2518 std::rotate(std::rbegin(p
.history
), std::rbegin(p
.history
) + 1, std::rend(p
.history
));
2519 p
.history
[THIS_MONTH
].production
= 0;
2520 p
.history
[THIS_MONTH
].transported
= 0;
2526 * Recompute #production_rate for current #prod_level.
2527 * This function is only valid when not using smooth economy.
2529 void Industry::RecomputeProductionMultipliers()
2531 const IndustrySpec
*indspec
= GetIndustrySpec(this->type
);
2532 assert(indspec
->UsesOriginalEconomy());
2534 /* Rates are rounded up, so e.g. oilrig always produces some passengers */
2535 for (auto &p
: this->produced
) {
2536 p
.rate
= ClampTo
<uint8_t>(CeilDiv(indspec
->production_rate
[&p
- this->produced
.data()] * this->prod_level
, PRODLEVEL_DEFAULT
));
2540 void Industry::FillCachedName() const
2542 auto tmp_params
= MakeParameters(this->index
);
2543 this->cached_name
= GetStringWithArgs(STR_INDUSTRY_NAME
, tmp_params
);
2546 void ClearAllIndustryCachedNames()
2548 for (Industry
*ind
: Industry::Iterate()) {
2549 ind
->cached_name
.clear();
2554 * Set the #probability and #min_number fields for the industry type \a it for a running game.
2555 * @param it Industry type.
2556 * @return At least one of the fields has changed value.
2558 bool IndustryTypeBuildData::GetIndustryTypeData(IndustryType it
)
2561 uint32_t probability
= GetIndustryGamePlayProbability(it
, &min_number
);
2562 bool changed
= min_number
!= this->min_number
|| probability
!= this->probability
;
2563 this->min_number
= min_number
;
2564 this->probability
= probability
;
2568 /** Decide how many industries of each type are needed. */
2569 void IndustryBuildData::SetupTargetCount()
2571 bool changed
= false;
2572 uint num_planned
= 0; // Number of industries planned in the industry build data.
2573 for (IndustryType it
= 0; it
< NUM_INDUSTRYTYPES
; it
++) {
2574 changed
|= this->builddata
[it
].GetIndustryTypeData(it
);
2575 num_planned
+= this->builddata
[it
].target_count
;
2577 uint total_amount
= this->wanted_inds
>> 16; // Desired total number of industries.
2578 changed
|= num_planned
!= total_amount
;
2579 if (!changed
) return; // All industries are still the same, no need to re-randomize.
2581 /* Initialize the target counts. */
2582 uint force_build
= 0; // Number of industries that should always be available.
2583 uint32_t total_prob
= 0; // Sum of probabilities.
2584 for (IndustryType it
= 0; it
< NUM_INDUSTRYTYPES
; it
++) {
2585 IndustryTypeBuildData
*ibd
= this->builddata
+ it
;
2586 force_build
+= ibd
->min_number
;
2587 ibd
->target_count
= ibd
->min_number
;
2588 total_prob
+= ibd
->probability
;
2591 if (total_prob
== 0) return; // No buildable industries.
2593 /* Subtract forced industries from the number of industries available for construction. */
2594 total_amount
= (total_amount
<= force_build
) ? 0 : total_amount
- force_build
;
2596 /* Assign number of industries that should be aimed for, by using the probability as a weight. */
2597 while (total_amount
> 0) {
2598 uint32_t r
= RandomRange(total_prob
);
2599 IndustryType it
= 0;
2600 while (r
>= this->builddata
[it
].probability
) {
2601 r
-= this->builddata
[it
].probability
;
2603 assert(it
< NUM_INDUSTRYTYPES
);
2605 assert(this->builddata
[it
].probability
> 0);
2606 this->builddata
[it
].target_count
++;
2612 * Try to create a random industry, during gameplay
2614 void IndustryBuildData::TryBuildNewIndustry()
2616 this->SetupTargetCount();
2618 int missing
= 0; // Number of industries that need to be build.
2619 uint count
= 0; // Number of industry types eligible for build.
2620 uint32_t total_prob
= 0; // Sum of probabilities.
2621 IndustryType forced_build
= NUM_INDUSTRYTYPES
; // Industry type that should be forcibly build.
2622 for (IndustryType it
= 0; it
< NUM_INDUSTRYTYPES
; it
++) {
2623 int difference
= this->builddata
[it
].target_count
- Industry::GetIndustryTypeCount(it
);
2624 missing
+= difference
;
2625 if (this->builddata
[it
].wait_count
> 0) continue; // This type may not be built now.
2626 if (difference
> 0) {
2627 if (Industry::GetIndustryTypeCount(it
) == 0 && this->builddata
[it
].min_number
> 0) {
2628 /* An industry that should exist at least once, is not available. Force it, trying the most needed one first. */
2629 if (forced_build
== NUM_INDUSTRYTYPES
||
2630 difference
> this->builddata
[forced_build
].target_count
- Industry::GetIndustryTypeCount(forced_build
)) {
2634 total_prob
+= difference
;
2639 if (EconomyIsInRecession() || (forced_build
== NUM_INDUSTRYTYPES
&& (missing
<= 0 || total_prob
== 0))) count
= 0; // Skip creation of an industry.
2642 /* If not forced, pick a weighted random industry to build.
2643 * For the case that count == 1, there is no need to draw a random number. */
2645 if (forced_build
!= NUM_INDUSTRYTYPES
) {
2648 /* Non-forced, select an industry type to build (weighted random). */
2649 uint32_t r
= 0; // Initialized to silence the compiler.
2650 if (count
> 1) r
= RandomRange(total_prob
);
2651 for (it
= 0; it
< NUM_INDUSTRYTYPES
; it
++) {
2652 if (this->builddata
[it
].wait_count
> 0) continue; // Type may not be built now.
2653 int difference
= this->builddata
[it
].target_count
- Industry::GetIndustryTypeCount(it
);
2654 if (difference
<= 0) continue; // Too many of this kind.
2655 if (count
== 1) break;
2656 if (r
< (uint
)difference
) break;
2659 assert(it
< NUM_INDUSTRYTYPES
&& this->builddata
[it
].target_count
> Industry::GetIndustryTypeCount(it
));
2662 /* Try to create the industry. */
2663 const Industry
*ind
= PlaceIndustry(it
, IACT_RANDOMCREATION
, false);
2664 if (ind
== nullptr) {
2665 this->builddata
[it
].wait_count
= this->builddata
[it
].max_wait
+ 1; // Compensate for decrementing below.
2666 this->builddata
[it
].max_wait
= std::min(1000, this->builddata
[it
].max_wait
+ 2);
2668 AdvertiseIndustryOpening(ind
);
2669 this->builddata
[it
].max_wait
= std::max(this->builddata
[it
].max_wait
/ 2, 1); // Reduce waiting time of the industry type.
2673 /* Decrement wait counters. */
2674 for (IndustryType it
= 0; it
< NUM_INDUSTRYTYPES
; it
++) {
2675 if (this->builddata
[it
].wait_count
> 0) this->builddata
[it
].wait_count
--;
2680 * Protects an industry from closure if the appropriate flags and conditions are met
2681 * INDUSTRYBEH_CANCLOSE_LASTINSTANCE must be set (which, by default, it is not) and the
2682 * count of industries of this type must one (or lower) in order to be protected
2684 * @param type IndustryType been queried
2685 * @result true if protection is on, false otherwise (except for oil wells)
2687 static bool CheckIndustryCloseDownProtection(IndustryType type
)
2689 const IndustrySpec
*indspec
= GetIndustrySpec(type
);
2691 /* oil wells (or the industries with that flag set) are always allowed to closedown */
2692 if ((indspec
->behaviour
& INDUSTRYBEH_DONT_INCR_PROD
) && _settings_game
.game_creation
.landscape
== LT_TEMPERATE
) return false;
2693 return (indspec
->behaviour
& INDUSTRYBEH_CANCLOSE_LASTINSTANCE
) == 0 && Industry::GetIndustryTypeCount(type
) <= 1;
2697 * Can given cargo type be accepted or produced by the industry?
2698 * @param cargo: Cargo type
2699 * @param ind: Industry
2700 * @param *c_accepts: Pointer to boolean for acceptance of cargo
2701 * @param *c_produces: Pointer to boolean for production of cargo
2702 * @return: \c *c_accepts is set when industry accepts the cargo type,
2703 * \c *c_produces is set when the industry produces the cargo type
2705 static void CanCargoServiceIndustry(CargoID cargo
, Industry
*ind
, bool *c_accepts
, bool *c_produces
)
2707 if (!IsValidCargoID(cargo
)) return;
2709 /* Check for acceptance of cargo */
2710 if (ind
->IsCargoAccepted(cargo
) && !IndustryTemporarilyRefusesCargo(ind
, cargo
)) *c_accepts
= true;
2712 /* Check for produced cargo */
2713 if (ind
->IsCargoProduced(cargo
)) *c_produces
= true;
2717 * Compute who can service the industry.
2719 * Here, 'can service' means that they have trains and stations close enough
2720 * to the industry with the right cargo type and the right orders (ie has the
2723 * @param ind: Industry being investigated.
2725 * @return: 0 if nobody can service the industry, 2 if the local company can
2726 * service the industry, and 1 otherwise (only competitors can service the
2729 int WhoCanServiceIndustry(Industry
*ind
)
2731 if (ind
->stations_near
.empty()) return 0; // No stations found at all => nobody services
2734 for (const Vehicle
*v
: Vehicle::Iterate()) {
2735 /* Is it worthwhile to try this vehicle? */
2736 if (v
->owner
!= _local_company
&& result
!= 0) continue;
2738 /* Check whether it accepts the right kind of cargo */
2739 bool c_accepts
= false;
2740 bool c_produces
= false;
2741 if (v
->type
== VEH_TRAIN
&& v
->IsFrontEngine()) {
2742 for (const Vehicle
*u
= v
; u
!= nullptr; u
= u
->Next()) {
2743 CanCargoServiceIndustry(u
->cargo_type
, ind
, &c_accepts
, &c_produces
);
2745 } else if (v
->type
== VEH_ROAD
|| v
->type
== VEH_SHIP
|| v
->type
== VEH_AIRCRAFT
) {
2746 CanCargoServiceIndustry(v
->cargo_type
, ind
, &c_accepts
, &c_produces
);
2750 if (!c_accepts
&& !c_produces
) continue; // Wrong cargo
2752 /* Check orders of the vehicle.
2753 * We cannot check the first of shared orders only, since the first vehicle in such a chain
2754 * may have a different cargo type.
2756 for (const Order
*o
: v
->Orders()) {
2757 if (o
->IsType(OT_GOTO_STATION
) && !(o
->GetUnloadType() & OUFB_TRANSFER
)) {
2758 /* Vehicle visits a station to load or unload */
2759 Station
*st
= Station::Get(o
->GetDestination());
2760 assert(st
!= nullptr);
2762 /* Same cargo produced by industry is dropped here => not serviced by vehicle v */
2763 if ((o
->GetUnloadType() & OUFB_UNLOAD
) && !c_accepts
) break;
2765 if (ind
->stations_near
.find(st
) != ind
->stations_near
.end()) {
2766 if (v
->owner
== _local_company
) return 2; // Company services industry
2767 result
= 1; // Competitor services industry
2776 * Report news that industry production has changed significantly
2778 * @param ind: Industry with changed production
2779 * @param type: Cargo type that has changed
2780 * @param percent: Percentage of change (>0 means increase, <0 means decrease)
2782 static void ReportNewsProductionChangeIndustry(Industry
*ind
, CargoID type
, int percent
)
2786 switch (WhoCanServiceIndustry(ind
)) {
2787 case 0: nt
= NT_INDUSTRY_NOBODY
; break;
2788 case 1: nt
= NT_INDUSTRY_OTHER
; break;
2789 case 2: nt
= NT_INDUSTRY_COMPANY
; break;
2790 default: NOT_REACHED();
2792 SetDParam(2, abs(percent
));
2793 SetDParam(0, CargoSpec::Get(type
)->name
);
2794 SetDParam(1, ind
->index
);
2795 AddIndustryNewsItem(
2796 percent
>= 0 ? STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH
: STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH
,
2802 static const uint PERCENT_TRANSPORTED_60
= 153;
2803 static const uint PERCENT_TRANSPORTED_80
= 204;
2806 * Change industry production or do closure
2807 * @param i Industry for which changes are performed
2808 * @param monthly true if it's the monthly call, false if it's the random call
2810 static void ChangeIndustryProduction(Industry
*i
, bool monthly
)
2812 StringID str
= STR_NULL
;
2813 bool closeit
= false;
2814 const IndustrySpec
*indspec
= GetIndustrySpec(i
->type
);
2815 bool standard
= false;
2816 bool suppress_message
= false;
2817 bool recalculate_multipliers
= false; ///< reinitialize production_rate to match prod_level
2818 /* use original economy for industries using production related callbacks */
2819 bool original_economy
= indspec
->UsesOriginalEconomy();
2822 int8_t increment
= 0;
2824 bool callback_enabled
= HasBit(indspec
->callback_mask
, monthly
? CBM_IND_MONTHLYPROD_CHANGE
: CBM_IND_PRODUCTION_CHANGE
);
2825 if (callback_enabled
) {
2826 uint16_t res
= GetIndustryCallback(monthly
? CBID_INDUSTRY_MONTHLYPROD_CHANGE
: CBID_INDUSTRY_PRODUCTION_CHANGE
, 0, Random(), i
, i
->type
, i
->location
.tile
);
2827 if (res
!= CALLBACK_FAILED
) { // failed callback means "do nothing"
2828 suppress_message
= HasBit(res
, 7);
2829 /* Get the custom message if any */
2830 if (HasBit(res
, 8)) str
= MapGRFStringID(indspec
->grf_prop
.grffile
->grfid
, GB(GetRegister(0x100), 0, 16));
2831 res
= GB(res
, 0, 4);
2833 default: NOT_REACHED();
2834 case 0x0: break; // Do nothing, but show the custom message if any
2835 case 0x1: div
= 1; break; // Halve industry production. If production reaches the quarter of the default, the industry is closed instead.
2836 case 0x2: mul
= 1; break; // Double industry production if it hasn't reached eight times of the original yet.
2837 case 0x3: closeit
= true; break; // The industry announces imminent closure, and is physically removed from the map next month.
2838 case 0x4: standard
= true; break; // Do the standard random production change as if this industry was a primary one.
2839 case 0x5: case 0x6: case 0x7: // Divide production by 4, 8, 16
2840 case 0x8: div
= res
- 0x3; break; // Divide production by 32
2841 case 0x9: case 0xA: case 0xB: // Multiply production by 4, 8, 16
2842 case 0xC: mul
= res
- 0x7; break; // Multiply production by 32
2843 case 0xD: // decrement production
2844 case 0xE: // increment production
2845 increment
= res
== 0x0D ? -1 : 1;
2847 case 0xF: // Set production to third byte of register 0x100
2848 i
->prod_level
= Clamp(GB(GetRegister(0x100), 16, 8), PRODLEVEL_MINIMUM
, PRODLEVEL_MAXIMUM
);
2849 recalculate_multipliers
= true;
2854 if (monthly
== original_economy
) return;
2855 if (!original_economy
&& _settings_game
.economy
.type
== ET_FROZEN
) return;
2856 if (indspec
->life_type
== INDUSTRYLIFE_BLACK_HOLE
) return;
2859 if (standard
|| (!callback_enabled
&& (indspec
->life_type
& (INDUSTRYLIFE_ORGANIC
| INDUSTRYLIFE_EXTRACTIVE
)) != 0)) {
2860 /* decrease or increase */
2861 bool only_decrease
= (indspec
->behaviour
& INDUSTRYBEH_DONT_INCR_PROD
) && _settings_game
.game_creation
.landscape
== LT_TEMPERATE
;
2863 if (original_economy
) {
2864 if (only_decrease
|| Chance16(1, 3)) {
2865 /* If more than 60% transported, 66% chance of increase, else 33% chance of increase */
2866 if (!only_decrease
&& (i
->GetProduced(0).history
[LAST_MONTH
].PctTransported() > PERCENT_TRANSPORTED_60
) != Chance16(1, 3)) {
2867 mul
= 1; // Increase production
2869 div
= 1; // Decrease production
2872 } else if (_settings_game
.economy
.type
== ET_SMOOTH
) {
2873 closeit
= !(i
->ctlflags
& (INDCTL_NO_CLOSURE
| INDCTL_NO_PRODUCTION_DECREASE
));
2874 for (auto &p
: i
->produced
) {
2875 if (!IsValidCargoID(p
.cargo
)) continue;
2876 uint32_t r
= Random();
2877 int old_prod
, new_prod
, percent
;
2878 /* If over 60% is transported, mult is 1, else mult is -1. */
2879 int mult
= (p
.history
[LAST_MONTH
].PctTransported() > PERCENT_TRANSPORTED_60
) ? 1 : -1;
2881 new_prod
= old_prod
= p
.rate
;
2883 /* For industries with only_decrease flags (temperate terrain Oil Wells),
2884 * the multiplier will always be -1 so they will only decrease. */
2885 if (only_decrease
) {
2887 /* For normal industries, if over 60% is transported, 33% chance for decrease.
2888 * Bonus for very high station ratings (over 80%): 16% chance for decrease. */
2889 } else if (Chance16I(1, ((p
.history
[LAST_MONTH
].PctTransported() > PERCENT_TRANSPORTED_80
) ? 6 : 3), r
)) {
2893 /* 4.5% chance for 3-23% (or 1 unit for very low productions) production change,
2894 * determined by mult value. If mult = 1 prod. increases, else (-1) it decreases. */
2895 if (Chance16I(1, 22, r
>> 16)) {
2896 new_prod
+= mult
* (std::max(((RandomRange(50) + 10) * old_prod
) >> 8, 1U));
2899 /* Prevent production to overflow or Oil Rig passengers to be over-"produced" */
2900 new_prod
= Clamp(new_prod
, 1, 255);
2901 if (IsValidCargoID(p
.cargo
) && p
.cargo
== GetCargoIDByLabel(CT_PASSENGERS
) && !(indspec
->behaviour
& INDUSTRYBEH_NO_PAX_PROD_CLAMP
)) {
2902 new_prod
= Clamp(new_prod
, 0, 16);
2905 /* If override flags are set, prevent actually changing production if any was decided on */
2906 if ((i
->ctlflags
& INDCTL_NO_PRODUCTION_DECREASE
) && new_prod
< old_prod
) continue;
2907 if ((i
->ctlflags
& INDCTL_NO_PRODUCTION_INCREASE
) && new_prod
> old_prod
) continue;
2909 /* Do not stop closing the industry when it has the lowest possible production rate */
2910 if (new_prod
== old_prod
&& old_prod
> 1) {
2915 percent
= (old_prod
== 0) ? 100 : (new_prod
* 100 / old_prod
- 100);
2918 /* Close the industry when it has the lowest possible production rate */
2919 if (new_prod
> 1) closeit
= false;
2921 if (abs(percent
) >= 10) {
2922 ReportNewsProductionChangeIndustry(i
, p
.cargo
, percent
);
2928 /* If override flags are set, prevent actually changing production if any was decided on */
2929 if ((i
->ctlflags
& INDCTL_NO_PRODUCTION_DECREASE
) && (div
> 0 || increment
< 0)) return;
2930 if ((i
->ctlflags
& INDCTL_NO_PRODUCTION_INCREASE
) && (mul
> 0 || increment
> 0)) return;
2931 if (i
->ctlflags
& INDCTL_EXTERNAL_PROD_LEVEL
) {
2937 if (!callback_enabled
&& (indspec
->life_type
& INDUSTRYLIFE_PROCESSING
)) {
2938 if (TimerGameEconomy::year
- i
->last_prod_year
>= PROCESSING_INDUSTRY_ABANDONMENT_YEARS
&& Chance16(1, original_economy
? 2 : 180)) {
2943 /* Increase if needed */
2944 while (mul
-- != 0 && i
->prod_level
< PRODLEVEL_MAXIMUM
) {
2945 i
->prod_level
= std::min
<int>(i
->prod_level
* 2, PRODLEVEL_MAXIMUM
);
2946 recalculate_multipliers
= true;
2947 if (str
== STR_NULL
) str
= indspec
->production_up_text
;
2950 /* Decrease if needed */
2951 while (div
-- != 0 && !closeit
) {
2952 if (i
->prod_level
== PRODLEVEL_MINIMUM
) {
2956 i
->prod_level
= std::max
<int>(i
->prod_level
/ 2, PRODLEVEL_MINIMUM
);
2957 recalculate_multipliers
= true;
2958 if (str
== STR_NULL
) str
= indspec
->production_down_text
;
2962 /* Increase or Decreasing the production level if needed */
2963 if (increment
!= 0) {
2964 if (increment
< 0 && i
->prod_level
== PRODLEVEL_MINIMUM
) {
2967 i
->prod_level
= ClampU(i
->prod_level
+ increment
, PRODLEVEL_MINIMUM
, PRODLEVEL_MAXIMUM
);
2968 recalculate_multipliers
= true;
2972 /* Recalculate production_rate
2973 * For non-smooth economy these should always be synchronized with prod_level */
2974 if (recalculate_multipliers
) i
->RecomputeProductionMultipliers();
2976 /* Close if needed and allowed */
2977 if (closeit
&& !CheckIndustryCloseDownProtection(i
->type
) && !(i
->ctlflags
& INDCTL_NO_CLOSURE
)) {
2978 i
->prod_level
= PRODLEVEL_CLOSURE
;
2979 SetWindowDirty(WC_INDUSTRY_VIEW
, i
->index
);
2980 str
= indspec
->closure_text
;
2983 if (!suppress_message
&& str
!= STR_NULL
) {
2985 /* Compute news category */
2987 nt
= NT_INDUSTRY_CLOSE
;
2988 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i
->index
));
2989 Game::NewEvent(new ScriptEventIndustryClose(i
->index
));
2991 switch (WhoCanServiceIndustry(i
)) {
2992 case 0: nt
= NT_INDUSTRY_NOBODY
; break;
2993 case 1: nt
= NT_INDUSTRY_OTHER
; break;
2994 case 2: nt
= NT_INDUSTRY_COMPANY
; break;
2995 default: NOT_REACHED();
2998 /* Set parameters of news string */
2999 if (str
> STR_LAST_STRINGID
) {
3000 SetDParam(0, STR_TOWN_NAME
);
3001 SetDParam(1, i
->town
->index
);
3002 SetDParam(2, indspec
->name
);
3003 } else if (closeit
) {
3004 SetDParam(0, STR_FORMAT_INDUSTRY_NAME
);
3005 SetDParam(1, i
->town
->index
);
3006 SetDParam(2, indspec
->name
);
3008 SetDParam(0, i
->index
);
3010 /* and report the news to the user */
3012 AddTileNewsItem(str
, nt
, i
->location
.tile
+ TileDiffXY(1, 1));
3014 AddIndustryNewsItem(str
, nt
, i
->index
);
3020 * Every economy day handler for the industry changes
3021 * Taking the original map size of 256*256, the number of random changes was always of just one unit.
3022 * But it cannot be the same on smaller or bigger maps. That number has to be scaled up or down.
3023 * For small maps, it implies that less than one change per month is required, while on bigger maps,
3024 * it would be way more. The daily loop handles those changes.
3026 static IntervalTimer
<TimerGameEconomy
> _economy_industries_daily({TimerGameEconomy::DAY
, TimerGameEconomy::Priority::INDUSTRY
}, [](auto)
3028 _economy
.industry_daily_change_counter
+= _economy
.industry_daily_increment
;
3030 /* Bits 16-31 of industry_construction_counter contain the number of industries to change/create today,
3031 * the lower 16 bit are a fractional part that might accumulate over several days until it
3032 * is sufficient for an industry. */
3033 uint16_t change_loop
= _economy
.industry_daily_change_counter
>> 16;
3035 /* Reset the active part of the counter, just keeping the "fractional part" */
3036 _economy
.industry_daily_change_counter
&= 0xFFFF;
3038 if (change_loop
== 0) {
3039 return; // Nothing to do? get out
3042 Backup
<CompanyID
> cur_company(_current_company
, OWNER_NONE
);
3044 /* perform the required industry changes for the day */
3046 uint perc
= 3; // Between 3% and 9% chance of creating a new industry.
3047 if ((_industry_builder
.wanted_inds
>> 16) > GetCurrentTotalNumberOfIndustries()) {
3048 perc
= std::min(9u, perc
+ (_industry_builder
.wanted_inds
>> 16) - GetCurrentTotalNumberOfIndustries());
3050 for (uint16_t j
= 0; j
< change_loop
; j
++) {
3051 if (Chance16(perc
, 100)) {
3052 _industry_builder
.TryBuildNewIndustry();
3054 Industry
*i
= Industry::GetRandom();
3056 ChangeIndustryProduction(i
, false);
3057 SetWindowDirty(WC_INDUSTRY_VIEW
, i
->index
);
3062 cur_company
.Restore();
3064 /* production-change */
3065 InvalidateWindowData(WC_INDUSTRY_DIRECTORY
, 0, IDIWD_PRODUCTION_CHANGE
);
3068 static IntervalTimer
<TimerGameEconomy
> _economy_industries_monthly({TimerGameEconomy::MONTH
, TimerGameEconomy::Priority::INDUSTRY
}, [](auto)
3070 Backup
<CompanyID
> cur_company(_current_company
, OWNER_NONE
);
3072 _industry_builder
.EconomyMonthlyLoop();
3074 for (Industry
*i
: Industry::Iterate()) {
3075 UpdateIndustryStatistics(i
);
3076 if (i
->prod_level
== PRODLEVEL_CLOSURE
) {
3079 ChangeIndustryProduction(i
, true);
3080 SetWindowDirty(WC_INDUSTRY_VIEW
, i
->index
);
3084 cur_company
.Restore();
3086 /* production-change */
3087 InvalidateWindowData(WC_INDUSTRY_DIRECTORY
, 0, IDIWD_PRODUCTION_CHANGE
);
3091 void InitializeIndustries()
3093 Industry::ResetIndustryCounts();
3094 _industry_sound_tile
= 0;
3096 _industry_builder
.Reset();
3099 /** Verify whether the generated industries are complete, and warn the user if not. */
3100 void CheckIndustries()
3103 for (IndustryType it
= 0; it
< NUM_INDUSTRYTYPES
; it
++) {
3104 if (Industry::GetIndustryTypeCount(it
) > 0) continue; // Types of existing industries can be skipped.
3106 bool force_at_least_one
;
3107 uint32_t chance
= GetScaledIndustryGenerationProbability(it
, &force_at_least_one
);
3108 if (chance
== 0 || !force_at_least_one
) continue; // Types that are not available can be skipped.
3110 const IndustrySpec
*is
= GetIndustrySpec(it
);
3111 SetDParam(0, is
->name
);
3112 ShowErrorMessage(STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES
, STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION
, WL_WARNING
);
3115 if (count
>= 3) break; // Don't swamp the user with errors.
3120 * Is an industry with the spec a raw industry?
3121 * @return true if it should be handled as a raw industry
3123 bool IndustrySpec::IsRawIndustry() const
3125 return (this->life_type
& (INDUSTRYLIFE_EXTRACTIVE
| INDUSTRYLIFE_ORGANIC
)) != 0;
3129 * Is an industry with the spec a processing industry?
3130 * @return true if it should be handled as a processing industry
3132 bool IndustrySpec::IsProcessingIndustry() const
3134 /* Lumber mills are neither raw nor processing */
3135 return (this->life_type
& INDUSTRYLIFE_PROCESSING
) != 0 &&
3136 (this->behaviour
& INDUSTRYBEH_CUT_TREES
) == 0;
3140 * Get the cost for constructing this industry
3141 * @return the cost (inflation corrected etc)
3143 Money
IndustrySpec::GetConstructionCost() const
3145 /* Building raw industries like secondary uses different price base */
3146 return (_price
[(_settings_game
.construction
.raw_industry_construction
== 1 && this->IsRawIndustry()) ?
3147 PR_BUILD_INDUSTRY_RAW
: PR_BUILD_INDUSTRY
] * this->cost_multiplier
) >> 8;
3151 * Get the cost for removing this industry
3152 * Take note that the cost will always be zero for non-grf industries.
3153 * Only if the grf author did specified a cost will it be applicable.
3154 * @return the cost (inflation corrected etc)
3156 Money
IndustrySpec::GetRemovalCost() const
3158 return (_price
[PR_CLEAR_INDUSTRY
] * this->removal_cost_multiplier
) >> 8;
3162 * Determines whether this industrytype uses standard/newgrf production changes.
3163 * @return true if original economy is used.
3165 bool IndustrySpec::UsesOriginalEconomy() const
3167 return _settings_game
.economy
.type
== ET_ORIGINAL
||
3168 HasBit(this->callback_mask
, CBM_IND_PRODUCTION_256_TICKS
) || HasBit(this->callback_mask
, CBM_IND_PRODUCTION_CARGO_ARRIVAL
) || // production callbacks
3169 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
3172 static CommandCost
TerraformTile_Industry(TileIndex tile
, DoCommandFlag flags
, int z_new
, Slope tileh_new
)
3174 if (AutoslopeEnabled()) {
3175 /* We imitate here TTDP's behaviour:
3176 * - Both new and old slope must not be steep.
3177 * - TileMaxZ must not be changed.
3178 * - Allow autoslope by default.
3179 * - Disallow autoslope if callback succeeds and returns non-zero.
3181 Slope tileh_old
= GetTileSlope(tile
);
3182 /* TileMaxZ must not be changed. Slopes must not be steep. */
3183 if (!IsSteepSlope(tileh_old
) && !IsSteepSlope(tileh_new
) && (GetTileMaxZ(tile
) == z_new
+ GetSlopeMaxZ(tileh_new
))) {
3184 const IndustryGfx gfx
= GetIndustryGfx(tile
);
3185 const IndustryTileSpec
*itspec
= GetIndustryTileSpec(gfx
);
3187 /* Call callback 3C 'disable autosloping for industry tiles'. */
3188 if (HasBit(itspec
->callback_mask
, CBM_INDT_AUTOSLOPE
)) {
3189 /* If the callback fails, allow autoslope. */
3190 uint16_t res
= GetIndustryTileCallback(CBID_INDTILE_AUTOSLOPE
, 0, 0, gfx
, Industry::GetByTile(tile
), tile
);
3191 if (res
== CALLBACK_FAILED
|| !ConvertBooleanCallback(itspec
->grf_prop
.grffile
, CBID_INDTILE_AUTOSLOPE
, res
)) return CommandCost(EXPENSES_CONSTRUCTION
, _price
[PR_BUILD_FOUNDATION
]);
3193 /* allow autoslope */
3194 return CommandCost(EXPENSES_CONSTRUCTION
, _price
[PR_BUILD_FOUNDATION
]);
3198 return Command
<CMD_LANDSCAPE_CLEAR
>::Do(flags
, tile
);
3201 extern const TileTypeProcs _tile_type_industry_procs
= {
3202 DrawTile_Industry
, // draw_tile_proc
3203 GetSlopePixelZ_Industry
, // get_slope_z_proc
3204 ClearTile_Industry
, // clear_tile_proc
3205 AddAcceptedCargo_Industry
, // add_accepted_cargo_proc
3206 GetTileDesc_Industry
, // get_tile_desc_proc
3207 GetTileTrackStatus_Industry
, // get_tile_track_status_proc
3208 ClickTile_Industry
, // click_tile_proc
3209 AnimateTile_Industry
, // animate_tile_proc
3210 TileLoop_Industry
, // tile_loop_proc
3211 ChangeTileOwner_Industry
, // change_tile_owner_proc
3212 nullptr, // add_produced_cargo_proc
3213 nullptr, // vehicle_enter_tile_proc
3214 GetFoundation_Industry
, // get_foundation_proc
3215 TerraformTile_Industry
, // terraform_tile_proc
3218 bool IndustryCompare::operator() (const IndustryListEntry
&lhs
, const IndustryListEntry
&rhs
) const
3220 /* Compare by distance first and use index as a tiebreaker. */
3221 return std::tie(lhs
.distance
, lhs
.industry
->index
) < std::tie(rhs
.distance
, rhs
.industry
->index
);
3225 * Remove unused industry accepted/produced slots -- entries after the last slot with valid cargo.
3226 * @param ind Industry to trim slots.
3228 void TrimIndustryAcceptedProduced(Industry
*ind
)
3230 auto ita
= std::find_if(std::rbegin(ind
->accepted
), std::rend(ind
->accepted
), [](const auto &a
) { return IsValidCargoID(a
.cargo
); });
3231 ind
->accepted
.erase(ita
.base(), std::end(ind
->accepted
));
3232 ind
->accepted
.shrink_to_fit();
3234 auto itp
= std::find_if(std::rbegin(ind
->produced
), std::rend(ind
->produced
), [](const auto &p
) { return IsValidCargoID(p
.cargo
); });
3235 ind
->produced
.erase(itp
.base(), std::end(ind
->produced
));
3236 ind
->produced
.shrink_to_fit();