OpenTTD Source 15.0-beta2
industry_cmd.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10#include "stdafx.h"
11#include "clear_map.h"
12#include "industry.h"
13#include "station_base.h"
14#include "landscape.h"
15#include "viewport_func.h"
16#include "command_func.h"
17#include "town.h"
18#include "news_func.h"
19#include "cheat_type.h"
20#include "company_base.h"
21#include "genworld.h"
22#include "tree_map.h"
23#include "newgrf_cargo.h"
24#include "newgrf_debug.h"
26#include "autoslope.h"
27#include "water.h"
28#include "strings_func.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"
35#include "ai/ai.hpp"
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"
41#include "error.h"
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"
50
51#include "table/strings.h"
52#include "table/industry_land.h"
54
55#include "safeguards.h"
56
57IndustryPool _industry_pool("Industry");
59
60void ShowIndustryViewWindow(IndustryID industry);
61void BuildOilRig(TileIndex tile);
62
63static uint8_t _industry_sound_ctr;
64static TileIndex _industry_sound_tile;
65
66std::array<std::vector<IndustryID>, NUM_INDUSTRYTYPES> Industry::industries;
67
68IndustrySpec _industry_specs[NUM_INDUSTRYTYPES];
69IndustryTileSpec _industry_tile_specs[NUM_INDUSTRYTILES];
71
72static int WhoCanServiceIndustry(Industry *ind);
73
81{
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{});
84
85 /* Enable only the current climate industries */
86 for (auto it = std::begin(_industry_specs); it != industry_insert; ++it) {
87 it->enabled = it->climate_availability.Test(_settings_game.game_creation.landscape);
88 }
89
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{});
92
93 /* Reset any overrides that have been set. */
94 _industile_mngr.ResetOverride();
95 _industry_mngr.ResetOverride();
96}
97
106IndustryType GetIndustryType(Tile tile)
107{
108 assert(IsTileType(tile, MP_INDUSTRY));
109
110 const Industry *ind = Industry::GetByTile(tile);
111 assert(ind != nullptr);
112 return ind->type;
113}
114
123const IndustrySpec *GetIndustrySpec(IndustryType thistype)
124{
125 assert(thistype < NUM_INDUSTRYTYPES);
126 return &_industry_specs[thistype];
127}
128
138{
139 assert(gfx < NUM_INDUSTRYTILES);
140 return &_industry_tile_specs[gfx];
141}
142
143Industry::~Industry()
144{
145 if (CleaningPool()) return;
146
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;
151
152 const bool has_neutral_station = this->neutral_station != nullptr;
153
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());
158
159 /* MakeWaterKeepingClass() can also handle 'land' */
160 MakeWaterKeepingClass(tile_cur, OWNER_NONE);
161 }
162 } else if (IsTileType(tile_cur, MP_STATION) && IsOilRig(tile_cur)) {
163 DeleteOilRig(tile_cur);
164 }
165 }
166
167 if (has_neutral_station) {
168 /* Remove possible docking tiles */
169 for (TileIndex tile_cur : this->location) {
171 }
172 }
173
174 if (GetIndustrySpec(this->type)->behaviour.Test(IndustryBehaviour::PlantFields)) {
175 TileArea ta = TileArea(this->location.tile, 0, 0).Expand(21);
176
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, IndustryID::Invalid());
182 }
183 }
184 }
185
186 /* don't let any disaster vehicle target invalid industry */
188
189 /* Clear the persistent storage. */
190 delete this->psa;
191
193 auto it = std::ranges::lower_bound(industries, this->index);
194 industries.erase(it);
195
199 DeleteNewGRFInspectWindow(GSF_INDUSTRIES, this->index);
200
204
205 for (Station *st : this->stations_near) {
206 st->RemoveIndustryToDeliver(this);
207 }
208}
209
215{
216 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, IDIWD_FORCE_REBUILD);
218}
219
220
226{
227 if (Industry::GetNumItems() == 0) return nullptr;
228 int num = RandomRange((uint16_t)Industry::GetNumItems());
229 size_t index = std::numeric_limits<size_t>::max();
230
231 while (num >= 0) {
232 num--;
233 index++;
234
235 /* Make sure we have a valid industry */
236 while (!Industry::IsValidID(index)) {
237 index++;
238 assert(index < Industry::GetPoolSize());
239 }
240 }
241
242 return Industry::Get(index);
243}
244
245
246static void IndustryDrawSugarMine(const TileInfo *ti)
247{
248 if (!IsIndustryCompleted(ti->tile)) return;
249
250 const DrawIndustryAnimationStruct *d = &_draw_industry_spec1[GetAnimationFrame(ti->tile)];
251
252 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_SIEVE + d->image_1, PAL_NONE, d->x, 0);
253
254 if (d->image_2 != 0) {
255 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_CLOUDS + d->image_2 - 1, PAL_NONE, 8, 41);
256 }
257
258 if (d->image_3 != 0) {
259 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_PILE + d->image_3 - 1, PAL_NONE,
260 _drawtile_proc1[d->image_3 - 1].x, _drawtile_proc1[d->image_3 - 1].y);
261 }
262}
263
264static void IndustryDrawToffeeQuarry(const TileInfo *ti)
265{
266 uint8_t x = 0;
267
268 if (IsIndustryCompleted(ti->tile)) {
269 x = _industry_anim_offs_toffee[GetAnimationFrame(ti->tile)];
270 if (x == 0xFF) {
271 x = 0;
272 }
273 }
274
275 AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_SHOVEL, PAL_NONE, 22 - x, 24 + x);
276 AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_TOFFEE, PAL_NONE, 6, 14);
277}
278
279static void IndustryDrawBubbleGenerator( const TileInfo *ti)
280{
281 if (IsIndustryCompleted(ti->tile)) {
282 AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_BUBBLE, PAL_NONE, 5, _industry_anim_offs_bubbles[GetAnimationFrame(ti->tile)]);
283 }
284 AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_SPRING, PAL_NONE, 3, 67);
285}
286
287static void IndustryDrawToyFactory(const TileInfo *ti)
288{
289 const DrawIndustryAnimationStruct *d = &_industry_anim_offs_toys[GetAnimationFrame(ti->tile)];
290
291 if (d->image_1 != 0xFF) {
292 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_CLAY, PAL_NONE, d->x, 96 + d->image_1);
293 }
294
295 if (d->image_2 != 0xFF) {
296 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_ROBOT, PAL_NONE, 16 - d->image_2 * 2, 100 + d->image_2);
297 }
298
299 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP, PAL_NONE, 7, d->image_3);
300 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP_HOLDER, PAL_NONE, 0, 42);
301}
302
303static void IndustryDrawCoalPlantSparks(const TileInfo *ti)
304{
305 if (IsIndustryCompleted(ti->tile)) {
306 uint8_t image = GetAnimationFrame(ti->tile);
307
308 if (image != 0 && image < 7) {
309 AddChildSpriteScreen(image + SPR_IT_POWER_PLANT_TRANSFORMERS,
310 PAL_NONE,
311 _coal_plant_sparks[image - 1].x,
312 _coal_plant_sparks[image - 1].y
313 );
314 }
315 }
316}
317
318typedef void IndustryDrawTileProc(const TileInfo *ti);
319static IndustryDrawTileProc * const _industry_draw_tile_procs[5] = {
320 IndustryDrawSugarMine,
321 IndustryDrawToffeeQuarry,
322 IndustryDrawBubbleGenerator,
323 IndustryDrawToyFactory,
324 IndustryDrawCoalPlantSparks,
325};
326
327static void DrawTile_Industry(TileInfo *ti)
328{
329 IndustryGfx gfx = GetIndustryGfx(ti->tile);
331 const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
332
333 /* Retrieve pointer to the draw industry tile struct */
334 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
335 /* Draw the tile using the specialized method of newgrf industrytile.
336 * DrawNewIndustry will return false if ever the resolver could not
337 * find any sprite to display. So in this case, we will jump on the
338 * substitute gfx instead. */
339 if (indts->grf_prop.GetSpriteGroup() != nullptr && DrawNewIndustryTile(ti, ind, gfx, indts)) {
340 return;
341 } else {
342 /* No sprite group (or no valid one) found, meaning no graphics associated.
343 * Use the substitute one instead */
344 if (indts->grf_prop.subst_id != INVALID_INDUSTRYTILE) {
345 gfx = indts->grf_prop.subst_id;
346 /* And point the industrytile spec accordingly */
347 indts = GetIndustryTileSpec(gfx);
348 }
349 }
350 }
351
352 const DrawBuildingsTileStruct *dits = &_industry_draw_tile_data[gfx << 2 | (indts->anim_state ?
355
356 SpriteID image = dits->ground.sprite;
357
358 /* DrawFoundation() modifies ti->z and ti->tileh */
360
361 /* If the ground sprite is the default flat water sprite, draw also canal/river borders.
362 * Do not do this if the tile's WaterClass is 'land'. */
363 if (image == SPR_FLAT_WATER_TILE && IsTileOnWater(ti->tile)) {
364 DrawWaterClassGround(ti);
365 } else {
366 DrawGroundSprite(image, GroundSpritePaletteTransform(image, dits->ground.pal, GENERAL_SPRITE_COLOUR(ind->random_colour)));
367 }
368
369 /* If industries are transparent and invisible, do not draw the upper part */
370 if (IsInvisibilitySet(TO_INDUSTRIES)) return;
371
372 /* Add industry on top of the ground? */
373 image = dits->building.sprite;
374 if (image != 0) {
375 AddSortableSpriteToDraw(image, SpriteLayoutPaletteTransform(image, dits->building.pal, GENERAL_SPRITE_COLOUR(ind->random_colour)),
376 ti->x + dits->subtile_x,
377 ti->y + dits->subtile_y,
378 dits->width,
379 dits->height,
380 dits->dz,
381 ti->z,
383
384 if (IsTransparencySet(TO_INDUSTRIES)) return;
385 }
386
387 {
388 int proc = dits->draw_proc - 1;
389 if (proc >= 0) _industry_draw_tile_procs[proc](ti);
390 }
391}
392
393static int GetSlopePixelZ_Industry(TileIndex tile, uint, uint, bool)
394{
395 return GetTileMaxPixelZ(tile);
396}
397
398static Foundation GetFoundation_Industry(TileIndex tile, Slope tileh)
399{
400 IndustryGfx gfx = GetIndustryGfx(tile);
401
402 /* For NewGRF industry tiles we might not be drawing a foundation. We need to
403 * account for this, as other structures should
404 * draw the wall of the foundation in this case.
405 */
406 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
407 const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
409 uint32_t callback_res = GetIndustryTileCallback(CBID_INDTILE_DRAW_FOUNDATIONS, 0, 0, gfx, Industry::GetByTile(tile), tile);
410 if (callback_res != CALLBACK_FAILED && !ConvertBooleanCallback(indts->grf_prop.grffile, CBID_INDTILE_DRAW_FOUNDATIONS, callback_res)) return FOUNDATION_NONE;
411 }
412 }
413 return FlatteningFoundation(tileh);
414}
415
416static void AddAcceptedCargo_Industry(TileIndex tile, CargoArray &acceptance, CargoTypes &always_accepted)
417{
418 IndustryGfx gfx = GetIndustryGfx(tile);
419 const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
420 const Industry *ind = Industry::GetByTile(tile);
421
422 /* Starting point for acceptance */
423 auto accepts_cargo = itspec->accepts_cargo;
424 auto cargo_acceptance = itspec->acceptance;
425
427 /* Copy all accepted cargoes from industry itself */
428 for (const auto &a : ind->accepted) {
429 auto pos = std::ranges::find(accepts_cargo, a.cargo);
430 if (pos == std::end(accepts_cargo)) {
431 /* Not found, insert */
432 pos = std::ranges::find(accepts_cargo, INVALID_CARGO);
433 if (pos == std::end(accepts_cargo)) continue; // nowhere to place, give up on this one
434 *pos = a.cargo;
435 }
436 cargo_acceptance[std::distance(std::begin(accepts_cargo), pos)] += 8;
437 }
438 }
439
441 /* Try callback for accepts list, if success override all existing accepts */
442 uint16_t res = GetIndustryTileCallback(CBID_INDTILE_ACCEPT_CARGO, 0, 0, gfx, Industry::GetByTile(tile), tile);
443 if (res != CALLBACK_FAILED) {
444 accepts_cargo.fill(INVALID_CARGO);
445 for (uint i = 0; i < INDUSTRY_ORIGINAL_NUM_INPUTS; i++) accepts_cargo[i] = GetCargoTranslation(GB(res, i * 5, 5), itspec->grf_prop.grffile);
446 }
447 }
448
450 /* Try callback for acceptance list, if success override all existing acceptance */
451 uint16_t res = GetIndustryTileCallback(CBID_INDTILE_CARGO_ACCEPTANCE, 0, 0, gfx, Industry::GetByTile(tile), tile);
452 if (res != CALLBACK_FAILED) {
453 cargo_acceptance.fill(0);
454 for (uint i = 0; i < INDUSTRY_ORIGINAL_NUM_INPUTS; i++) cargo_acceptance[i] = GB(res, i * 4, 4);
455 }
456 }
457
458 for (uint8_t i = 0; i < std::size(itspec->accepts_cargo); i++) {
459 CargoType cargo = accepts_cargo[i];
460 if (!IsValidCargoType(cargo) || cargo_acceptance[i] <= 0) continue; // work only with valid cargoes
461
462 /* Add accepted cargo */
463 acceptance[cargo] += cargo_acceptance[i];
464
465 /* Maybe set 'always accepted' bit (if it's not set already) */
466 if (HasBit(always_accepted, cargo)) continue;
467
468 /* Test whether the industry itself accepts the cargo type */
469 if (ind->IsCargoAccepted(cargo)) continue;
470
471 /* If the industry itself doesn't accept this cargo, set 'always accepted' bit */
472 SetBit(always_accepted, cargo);
473 }
474}
475
476static void GetTileDesc_Industry(TileIndex tile, TileDesc &td)
477{
478 const Industry *i = Industry::GetByTile(tile);
479 const IndustrySpec *is = GetIndustrySpec(i->type);
480
481 td.owner[0] = i->owner;
482 td.str = is->name;
483 if (!IsIndustryCompleted(tile)) {
484 td.dparam = td.str;
485 td.str = STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION;
486 }
487
488 if (is->grf_prop.HasGrfFile()) {
490 }
491}
492
493static CommandCost ClearTile_Industry(TileIndex tile, DoCommandFlags flags)
494{
495 Industry *i = Industry::GetByTile(tile);
496 const IndustrySpec *indspec = GetIndustrySpec(i->type);
497
498 /* water can destroy industries
499 * in editor you can bulldoze industries
500 * with magic_bulldozer cheat you can destroy industries
501 * (area around OILRIG is water, so water shouldn't flood it
502 */
503 if ((_current_company != OWNER_WATER && _game_mode != GM_EDITOR &&
505 flags.Test(DoCommandFlag::Auto) ||
508 HasBit(GetIndustryTileSpec(GetIndustryGfx(tile))->slopes_refused, 5)))) {
509
510 if (flags.Test(DoCommandFlag::Auto)) {
511 return CommandCostWithParam(STR_ERROR_GENERIC_OBJECT_IN_THE_WAY, indspec->name);
512 }
514 }
515
516 if (flags.Test(DoCommandFlag::Execute)) {
517 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index));
518 Game::NewEvent(new ScriptEventIndustryClose(i->index));
519 delete i;
520 }
522}
523
530{
531 Industry *i = Industry::GetByTile(tile);
532 const IndustrySpec *indspec = GetIndustrySpec(i->type);
533 bool moved_cargo = false;
534
535 for (auto &p : i->produced) {
536 uint cw = ClampTo<uint8_t>(p.waiting);
537 if (cw > indspec->minimal_cargo && IsValidCargoType(p.cargo)) {
538 p.waiting -= cw;
539
540 /* fluctuating economy? */
541 if (EconomyIsInRecession()) cw = (cw + 1) / 2;
542
543 p.history[THIS_MONTH].production += cw;
544
545 uint am = MoveGoodsToStation(p.cargo, cw, {i->index, SourceType::Industry}, i->stations_near, i->exclusive_consumer);
546 p.history[THIS_MONTH].transported += am;
547
548 moved_cargo |= (am != 0);
549 }
550 }
551
552 return moved_cargo;
553}
554
555static void AnimateSugarSieve(TileIndex tile)
556{
557 uint8_t m = GetAnimationFrame(tile) + 1;
558
560 switch (m & 7) {
561 case 2: SndPlayTileFx(SND_2D_SUGAR_MINE_1, tile); break;
562 case 6: SndPlayTileFx(SND_29_SUGAR_MINE_2, tile); break;
563 }
564 }
565
566 if (m >= 96) {
567 m = 0;
568 DeleteAnimatedTile(tile);
569 }
570 SetAnimationFrame(tile, m);
571
573}
574
575static void AnimateToffeeQuarry(TileIndex tile)
576{
577 uint8_t m = GetAnimationFrame(tile);
578
579 if (_industry_anim_offs_toffee[m] == 0xFF && _settings_client.sound.ambient) {
580 SndPlayTileFx(SND_30_TOFFEE_QUARRY, tile);
581 }
582
583 if (++m >= 70) {
584 m = 0;
585 DeleteAnimatedTile(tile);
586 }
587 SetAnimationFrame(tile, m);
588
590}
591
592static void AnimateBubbleCatcher(TileIndex tile)
593{
594 uint8_t m = GetAnimationFrame(tile);
595
596 if (++m >= 40) {
597 m = 0;
598 DeleteAnimatedTile(tile);
599 }
600 SetAnimationFrame(tile, m);
601
603}
604
605static void AnimatePowerPlantSparks(TileIndex tile)
606{
607 uint8_t m = GetAnimationFrame(tile);
608 if (m == 6) {
609 SetAnimationFrame(tile, 0);
610 DeleteAnimatedTile(tile);
611 } else {
612 SetAnimationFrame(tile, m + 1);
613 }
615}
616
617static void AnimateToyFactory(TileIndex tile)
618{
619 uint8_t m = GetAnimationFrame(tile) + 1;
620
621 switch (m) {
622 case 1: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2C_TOY_FACTORY_1, tile); break;
623 case 23: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2B_TOY_FACTORY_2, tile); break;
624 case 28: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2A_TOY_FACTORY_3, tile); break;
625 default:
626 if (m >= 50) {
627 int n = GetIndustryAnimationLoop(tile) + 1;
628 m = 0;
629 if (n >= 8) {
630 n = 0;
631 DeleteAnimatedTile(tile);
632 }
634 }
635 }
636
637 SetAnimationFrame(tile, m);
639}
640
641static void AnimatePlasticFountain(TileIndex tile, IndustryGfx gfx)
642{
643 gfx = (gfx < GFX_PLASTIC_FOUNTAIN_ANIMATED_8) ? gfx + 1 : GFX_PLASTIC_FOUNTAIN_ANIMATED_1;
644 SetIndustryGfx(tile, gfx);
646}
647
648static void AnimateOilWell(TileIndex tile, IndustryGfx gfx)
649{
650 bool b = Chance16(1, 7);
651 uint8_t m = GetAnimationFrame(tile) + 1;
652 if (m == 4 && (m = 0, ++gfx) == GFX_OILWELL_ANIMATED_3 + 1 && (gfx = GFX_OILWELL_ANIMATED_1, b)) {
653 SetIndustryGfx(tile, GFX_OILWELL_NOT_ANIMATED);
655 DeleteAnimatedTile(tile);
656 } else {
657 SetAnimationFrame(tile, m);
658 SetIndustryGfx(tile, gfx);
659 }
661}
662
663static void AnimateMineTower(TileIndex tile)
664{
665 int state = TimerGameTick::counter & 0x7FF;
666
667 if ((state -= 0x400) < 0) return;
668
669 if (state < 0x1A0) {
670 if (state < 0x20 || state >= 0x180) {
671 uint8_t m = GetAnimationFrame(tile);
672 if (!(m & 0x40)) {
673 SetAnimationFrame(tile, m | 0x40);
674 if (_settings_client.sound.ambient) SndPlayTileFx(SND_0B_MINE, tile);
675 }
676 if (state & 7) return;
677 } else {
678 if (state & 3) return;
679 }
680 uint8_t m = (GetAnimationFrame(tile) + 1) | 0x40;
681 if (m > 0xC2) m = 0xC0;
682 SetAnimationFrame(tile, m);
684 } else if (state >= 0x200 && state < 0x3A0) {
685 int i = (state < 0x220 || state >= 0x380) ? 7 : 3;
686 if (state & i) return;
687
688 uint8_t m = (GetAnimationFrame(tile) & 0xBF) - 1;
689 if (m < 0x80) m = 0x82;
690 SetAnimationFrame(tile, m);
692 }
693}
694
695static void AnimateTile_Industry(TileIndex tile)
696{
697 IndustryGfx gfx = GetIndustryGfx(tile);
698
699 if (GetIndustryTileSpec(gfx)->animation.status != ANIM_STATUS_NO_ANIMATION) {
700 AnimateNewIndustryTile(tile);
701 return;
702 }
703
704 switch (gfx) {
705 case GFX_SUGAR_MINE_SIEVE:
706 if ((TimerGameTick::counter & 1) == 0) AnimateSugarSieve(tile);
707 break;
708
709 case GFX_TOFFEE_QUARY:
710 if ((TimerGameTick::counter & 3) == 0) AnimateToffeeQuarry(tile);
711 break;
712
713 case GFX_BUBBLE_CATCHER:
714 if ((TimerGameTick::counter & 1) == 0) AnimateBubbleCatcher(tile);
715 break;
716
717 case GFX_POWERPLANT_SPARKS:
718 if ((TimerGameTick::counter & 3) == 0) AnimatePowerPlantSparks(tile);
719 break;
720
721 case GFX_TOY_FACTORY:
722 if ((TimerGameTick::counter & 1) == 0) AnimateToyFactory(tile);
723 break;
724
725 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
726 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
727 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
728 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
729 if ((TimerGameTick::counter & 3) == 0) AnimatePlasticFountain(tile, gfx);
730 break;
731
732 case GFX_OILWELL_ANIMATED_1:
733 case GFX_OILWELL_ANIMATED_2:
734 case GFX_OILWELL_ANIMATED_3:
735 if ((TimerGameTick::counter & 7) == 0) AnimateOilWell(tile, gfx);
736 break;
737
738 case GFX_COAL_MINE_TOWER_ANIMATED:
739 case GFX_COPPER_MINE_TOWER_ANIMATED:
740 case GFX_GOLD_MINE_TOWER_ANIMATED:
741 AnimateMineTower(tile);
742 break;
743 }
744}
745
746static void CreateChimneySmoke(TileIndex tile)
747{
748 uint x = TileX(tile) * TILE_SIZE;
749 uint y = TileY(tile) * TILE_SIZE;
750 int z = GetTileMaxPixelZ(tile);
751
752 CreateEffectVehicle(x + 15, y + 14, z + 59, EV_CHIMNEY_SMOKE);
753}
754
755static void MakeIndustryTileBigger(TileIndex tile)
756{
757 uint8_t cnt = GetIndustryConstructionCounter(tile) + 1;
758 if (cnt != 4) {
760 return;
761 }
762
763 uint8_t stage = GetIndustryConstructionStage(tile) + 1;
765 SetIndustryConstructionStage(tile, stage);
766 StartStopIndustryTileAnimation(tile, IAT_CONSTRUCTION_STATE_CHANGE);
767 if (stage == INDUSTRY_COMPLETED) SetIndustryCompleted(tile);
768
770
771 if (!IsIndustryCompleted(tile)) return;
772
773 IndustryGfx gfx = GetIndustryGfx(tile);
774 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
775 /* New industries are already animated on construction. */
776 return;
777 }
778
779 switch (gfx) {
780 case GFX_POWERPLANT_CHIMNEY:
781 CreateChimneySmoke(tile);
782 break;
783
784 case GFX_OILRIG_1: {
785 /* Do not require an industry tile to be after the first two GFX_OILRIG_1
786 * tiles (like the default oil rig). Do a proper check to ensure the
787 * tiles belong to the same industry and based on that build the oil rig's
788 * station. */
789 TileIndex other = tile + TileDiffXY(0, 1);
790
791 if (IsTileType(other, MP_INDUSTRY) &&
792 GetIndustryGfx(other) == GFX_OILRIG_1 &&
793 GetIndustryIndex(tile) == GetIndustryIndex(other)) {
794 BuildOilRig(tile);
795 }
796 break;
797 }
798
799 case GFX_TOY_FACTORY:
800 case GFX_BUBBLE_CATCHER:
801 case GFX_TOFFEE_QUARY:
802 SetAnimationFrame(tile, 0);
804 break;
805
806 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
807 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
808 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
809 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
810 AddAnimatedTile(tile, false);
811 break;
812 }
813}
814
815static void TileLoopIndustry_BubbleGenerator(TileIndex tile)
816{
817 static const int8_t _bubble_spawn_location[3][4] = {
818 { 11, 0, -4, -14 },
819 { -4, -10, -4, 1 },
820 { 49, 59, 60, 65 },
821 };
822
823 if (_settings_client.sound.ambient) SndPlayTileFx(SND_2E_BUBBLE_GENERATOR, tile);
824
825 int dir = Random() & 3;
826
828 TileX(tile) * TILE_SIZE + _bubble_spawn_location[0][dir],
829 TileY(tile) * TILE_SIZE + _bubble_spawn_location[1][dir],
830 _bubble_spawn_location[2][dir],
832 );
833
834 if (v != nullptr) v->animation_substate = dir;
835}
836
837static void TileLoop_Industry(TileIndex tile)
838{
839 if (IsTileOnWater(tile)) TileLoop_Water(tile);
840
841 /* Normally this doesn't happen, but if an industry NewGRF is removed
842 * an industry that was previously build on water can now be flooded.
843 * If this happens the tile is no longer an industry tile after
844 * returning from TileLoop_Water. */
845 if (!IsTileType(tile, MP_INDUSTRY)) return;
846
848
849 if (!IsIndustryCompleted(tile)) {
850 MakeIndustryTileBigger(tile);
851 return;
852 }
853
854 if (_game_mode == GM_EDITOR) return;
855
856 if (TransportIndustryGoods(tile) && !StartStopIndustryTileAnimation(Industry::GetByTile(tile), IAT_INDUSTRY_DISTRIBUTES_CARGO)) {
858
859 if (newgfx != INDUSTRYTILE_NOANIM) {
862 SetIndustryGfx(tile, newgfx);
864 return;
865 }
866 }
867
868 if (StartStopIndustryTileAnimation(tile, IAT_TILELOOP)) return;
869
870 IndustryGfx newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_next;
871 if (newgfx != INDUSTRYTILE_NOANIM) {
873 SetIndustryGfx(tile, newgfx);
875 return;
876 }
877
878 IndustryGfx gfx = GetIndustryGfx(tile);
879 switch (gfx) {
880 case GFX_COAL_MINE_TOWER_NOT_ANIMATED:
881 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED:
882 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED:
883 if (!(TimerGameTick::counter & 0x400) && Chance16(1, 2)) {
884 switch (gfx) {
885 case GFX_COAL_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COAL_MINE_TOWER_ANIMATED; break;
886 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_ANIMATED; break;
887 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_ANIMATED; break;
888 }
889 SetIndustryGfx(tile, gfx);
890 SetAnimationFrame(tile, 0x80);
891 AddAnimatedTile(tile);
892 }
893 break;
894
895 case GFX_OILWELL_NOT_ANIMATED:
896 if (Chance16(1, 6)) {
897 SetIndustryGfx(tile, GFX_OILWELL_ANIMATED_1);
898 SetAnimationFrame(tile, 0);
899 AddAnimatedTile(tile);
900 }
901 break;
902
903 case GFX_COAL_MINE_TOWER_ANIMATED:
904 case GFX_COPPER_MINE_TOWER_ANIMATED:
905 case GFX_GOLD_MINE_TOWER_ANIMATED:
906 if (!(TimerGameTick::counter & 0x400)) {
907 switch (gfx) {
908 case GFX_COAL_MINE_TOWER_ANIMATED: gfx = GFX_COAL_MINE_TOWER_NOT_ANIMATED; break;
909 case GFX_COPPER_MINE_TOWER_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_NOT_ANIMATED; break;
910 case GFX_GOLD_MINE_TOWER_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_NOT_ANIMATED; break;
911 }
912 SetIndustryGfx(tile, gfx);
915 DeleteAnimatedTile(tile);
917 }
918 break;
919
920 case GFX_POWERPLANT_SPARKS:
921 if (Chance16(1, 3)) {
922 if (_settings_client.sound.ambient) SndPlayTileFx(SND_0C_POWER_STATION, tile);
923 AddAnimatedTile(tile);
924 }
925 break;
926
927 case GFX_COPPER_MINE_CHIMNEY:
929 break;
930
931
932 case GFX_TOY_FACTORY: {
933 Industry *i = Industry::GetByTile(tile);
934 if (i->was_cargo_delivered) {
935 i->was_cargo_delivered = false;
937 AddAnimatedTile(tile);
938 }
939 }
940 break;
941
942 case GFX_BUBBLE_GENERATOR:
943 TileLoopIndustry_BubbleGenerator(tile);
944 break;
945
946 case GFX_TOFFEE_QUARY:
947 AddAnimatedTile(tile);
948 break;
949
950 case GFX_SUGAR_MINE_SIEVE:
951 if (Chance16(1, 3)) AddAnimatedTile(tile);
952 break;
953 }
954}
955
956static bool ClickTile_Industry(TileIndex tile)
957{
958 ShowIndustryViewWindow(GetIndustryIndex(tile));
959 return true;
960}
961
962static TrackStatus GetTileTrackStatus_Industry(TileIndex, TransportType, uint, DiagDirection)
963{
964 return 0;
965}
966
967static void ChangeTileOwner_Industry(TileIndex tile, Owner old_owner, Owner new_owner)
968{
969 /* If the founder merges, the industry was created by the merged company */
970 Industry *i = Industry::GetByTile(tile);
971 if (i->founder == old_owner) i->founder = (new_owner == INVALID_OWNER) ? OWNER_NONE : new_owner;
972
973 if (i->exclusive_supplier == old_owner) i->exclusive_supplier = new_owner;
974 if (i->exclusive_consumer == old_owner) i->exclusive_consumer = new_owner;
975}
976
983{
984 /* Check for industry tile */
985 if (!IsTileType(tile, MP_INDUSTRY)) return false;
986
987 const Industry *ind = Industry::GetByTile(tile);
988
989 /* Check for organic industry (i.e. not processing or extractive) */
991
992 /* Check for wood production */
993 return std::any_of(std::begin(ind->produced), std::end(ind->produced), [](const auto &p) { return IsValidCargoType(p.cargo) && CargoSpec::Get(p.cargo)->label == CT_WOOD; });
994}
995
996static const uint8_t _plantfarmfield_type[] = {1, 1, 1, 1, 1, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6};
997
1005static bool IsSuitableForFarmField(TileIndex tile, bool allow_fields)
1006{
1007 switch (GetTileType(tile)) {
1008 case MP_CLEAR: return !IsSnowTile(tile) && !IsClearGround(tile, CLEAR_DESERT) && (allow_fields || !IsClearGround(tile, CLEAR_FIELDS));
1009 case MP_TREES: return GetTreeGround(tile) != TREE_GROUND_SHORE;
1010 default: return false;
1011 }
1012}
1013
1021static void SetupFarmFieldFence(TileIndex tile, int size, uint8_t type, DiagDirection side)
1022{
1024 TileIndexDiff neighbour_diff = TileOffsByDiagDir(side);
1025
1026 do {
1027 tile = Map::WrapToMap(tile);
1028
1029 if (IsTileType(tile, MP_CLEAR) && IsClearGround(tile, CLEAR_FIELDS)) {
1030 TileIndex neighbour = tile + neighbour_diff;
1031 if (!IsTileType(neighbour, MP_CLEAR) || !IsClearGround(neighbour, CLEAR_FIELDS) || GetFence(neighbour, ReverseDiagDir(side)) == 0) {
1032 /* Add fence as long as neighbouring tile does not already have a fence in the same position. */
1033 uint8_t or_ = type;
1034
1035 if (or_ == 1 && Chance16(1, 7)) or_ = 2;
1036
1037 SetFence(tile, side, or_);
1038 }
1039 }
1040
1041 tile += diff;
1042 } while (--size);
1043}
1044
1045static void PlantFarmField(TileIndex tile, IndustryID industry)
1046{
1047 if (_settings_game.game_creation.landscape == LandscapeType::Arctic) {
1048 if (GetTileZ(tile) + 2 >= GetSnowLine()) return;
1049 }
1050
1051 /* determine field size */
1052 uint32_t r = (Random() & 0x303) + 0x404;
1053 if (_settings_game.game_creation.landscape == LandscapeType::Arctic) r += 0x404;
1054 uint size_x = GB(r, 0, 8);
1055 uint size_y = GB(r, 8, 8);
1056
1057 TileArea ta(tile - TileDiffXY(std::min(TileX(tile), size_x / 2), std::min(TileY(tile), size_y / 2)), size_x, size_y);
1058 ta.ClampToMap();
1059
1060 if (ta.w == 0 || ta.h == 0) return;
1061
1062 /* check the amount of bad tiles */
1063 int count = 0;
1064 for (TileIndex cur_tile : ta) {
1065 assert(cur_tile < Map::Size());
1066 count += IsSuitableForFarmField(cur_tile, false);
1067 }
1068 if (count * 2 < ta.w * ta.h) return;
1069
1070 /* determine type of field */
1071 r = Random();
1072 uint counter = GB(r, 5, 3);
1073 uint field_type = GB(r, 8, 8) * 9 >> 8;
1074
1075 /* make field */
1076 for (TileIndex cur_tile : ta) {
1077 assert(cur_tile < Map::Size());
1078 if (IsSuitableForFarmField(cur_tile, true)) {
1079 MakeField(cur_tile, field_type, industry);
1080 SetClearCounter(cur_tile, counter);
1081 MarkTileDirtyByTile(cur_tile);
1082 }
1083 }
1084
1085 int type = 3;
1086 if (_settings_game.game_creation.landscape != LandscapeType::Arctic && _settings_game.game_creation.landscape != LandscapeType::Tropic) {
1087 type = _plantfarmfield_type[Random() & 0xF];
1088 }
1089
1090 SetupFarmFieldFence(ta.tile, ta.h, type, DIAGDIR_NE);
1091 SetupFarmFieldFence(ta.tile, ta.w, type, DIAGDIR_NW);
1092 SetupFarmFieldFence(ta.tile + TileDiffXY(ta.w - 1, 0), ta.h, type, DIAGDIR_SW);
1093 SetupFarmFieldFence(ta.tile + TileDiffXY(0, ta.h - 1), ta.w, type, DIAGDIR_SE);
1094}
1095
1096void PlantRandomFarmField(const Industry *i)
1097{
1098 int x = i->location.w / 2 + Random() % 31 - 16;
1099 int y = i->location.h / 2 + Random() % 31 - 16;
1100
1101 TileIndex tile = TileAddWrap(i->location.tile, x, y);
1102
1103 if (tile != INVALID_TILE) PlantFarmField(tile, i->index);
1104}
1105
1111static bool SearchLumberMillTrees(TileIndex tile, void *)
1112{
1114 /* found a tree */
1115
1117
1118 _industry_sound_ctr = 1;
1119 _industry_sound_tile = tile;
1120 if (_settings_client.sound.ambient) SndPlayTileFx(SND_38_LUMBER_MILL_1, tile);
1121
1123
1124 cur_company.Restore();
1125 return true;
1126 }
1127 return false;
1128}
1129
1135{
1136 /* Don't process lumber mill if cargo is not set up correctly. */
1137 auto itp = std::begin(i->produced);
1138 if (itp == std::end(i->produced) || !IsValidCargoType(itp->cargo)) return;
1139
1140 /* We only want to cut trees if all tiles are completed. */
1141 for (TileIndex tile_cur : i->location) {
1142 if (i->TileBelongsToIndustry(tile_cur)) {
1143 if (!IsIndustryCompleted(tile_cur)) return;
1144 }
1145 }
1146
1147 TileIndex tile = i->location.tile;
1148 if (CircularTileSearch(&tile, 40, SearchLumberMillTrees, nullptr)) { // 40x40 tiles to search.
1149 itp->waiting = ClampTo<uint16_t>(itp->waiting + ScaleByCargoScale(45, false)); // Found a tree, add according value to waiting cargo.
1150 }
1151}
1152
1158static void ProduceIndustryGoodsHelper(Industry *i, bool scale)
1159{
1160 for (auto &p : i->produced) {
1161 if (!IsValidCargoType(p.cargo)) continue;
1162
1163 uint16_t amount = p.rate;
1164 if (scale) amount = ScaleByCargoScale(amount, false);
1165
1166 p.waiting = ClampTo<uint16_t>(p.waiting + amount);
1167 }
1168}
1169
1170static void ProduceIndustryGoods(Industry *i)
1171{
1172 const IndustrySpec *indsp = GetIndustrySpec(i->type);
1173
1174 /* play a sound? */
1175 if ((i->counter & 0x3F) == 0) {
1176 uint32_t r;
1177 if (Chance16R(1, 14, r) && !indsp->random_sounds.empty() && _settings_client.sound.ambient) {
1178 if (std::any_of(std::begin(i->produced), std::end(i->produced), [](const auto &p) { return p.history[LAST_MONTH].production > 0; })) {
1179 /* Play sound since last month had production */
1180 SndPlayTileFx(
1181 static_cast<SoundFx>(indsp->random_sounds[((r >> 16) * indsp->random_sounds.size()) >> 16]),
1182 i->location.tile);
1183 }
1184 }
1185 }
1186
1187 i->counter--;
1188
1189 /* If using an industry callback, scale the callback interval by cargo scale percentage. */
1194 }
1195 }
1196
1197 /*
1198 * All other production and special effects happen every 256 ticks, and cargo production is just scaled by the cargo scale percentage.
1199 * 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.
1200 */
1201 if ((i->counter % Ticks::INDUSTRY_PRODUCE_TICKS) == 0) {
1202 /* Handle non-callback cargo production. */
1204
1205 IndustryBehaviours indbehav = indsp->behaviour;
1206
1207 if (indbehav.Test(IndustryBehaviour::PlantFields)) {
1208 uint16_t cb_res = CALLBACK_FAILED;
1211 }
1212
1213 bool plant;
1214 if (cb_res != CALLBACK_FAILED) {
1216 } else {
1217 plant = Chance16(1, 8);
1218 }
1219
1220 if (plant) PlantRandomFarmField(i);
1221 }
1222 if (indbehav.Test(IndustryBehaviour::CutTrees)) {
1223 uint16_t cb_res = CALLBACK_FAILED;
1226 }
1227
1228 bool cut;
1229 if (cb_res != CALLBACK_FAILED) {
1231 } else {
1232 cut = ((i->counter % Ticks::INDUSTRY_CUT_TREE_TICKS) == 0);
1233 }
1234
1235 if (cut) ChopLumberMillTrees(i);
1236 }
1237
1239 StartStopIndustryTileAnimation(i, IAT_INDUSTRY_TICK);
1240 }
1241}
1242
1243void OnTick_Industry()
1244{
1245 if (_industry_sound_ctr != 0) {
1246 _industry_sound_ctr++;
1247
1248 if (_industry_sound_ctr == 75) {
1249 if (_settings_client.sound.ambient) SndPlayTileFx(SND_37_LUMBER_MILL_2, _industry_sound_tile);
1250 } else if (_industry_sound_ctr == 160) {
1251 _industry_sound_ctr = 0;
1252 if (_settings_client.sound.ambient) SndPlayTileFx(SND_36_LUMBER_MILL_3, _industry_sound_tile);
1253 }
1254 }
1255
1256 if (_game_mode == GM_EDITOR) return;
1257
1258 for (Industry *i : Industry::Iterate()) {
1259 ProduceIndustryGoods(i);
1260 }
1261}
1262
1268{
1269 return CommandCost();
1270}
1271
1278{
1279 if (_settings_game.game_creation.landscape == LandscapeType::Arctic) {
1280 if (GetTileZ(tile) < HighestSnowLine() + 2) {
1281 return CommandCost(STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED);
1282 }
1283 }
1284 return CommandCost();
1285}
1286
1294static bool CheckScaledDistanceFromEdge(TileIndex tile, uint maxdist)
1295{
1296 uint maxdist_x = maxdist;
1297 uint maxdist_y = maxdist;
1298
1299 if (Map::SizeX() > 256) maxdist_x *= Map::SizeX() / 256;
1300 if (Map::SizeY() > 256) maxdist_y *= Map::SizeY() / 256;
1301
1302 if (DistanceFromEdgeDir(tile, DIAGDIR_NE) < maxdist_x) return true;
1303 if (DistanceFromEdgeDir(tile, DIAGDIR_NW) < maxdist_y) return true;
1304 if (DistanceFromEdgeDir(tile, DIAGDIR_SW) < maxdist_x) return true;
1305 if (DistanceFromEdgeDir(tile, DIAGDIR_SE) < maxdist_y) return true;
1306
1307 return false;
1308}
1309
1316{
1317 if (_game_mode == GM_EDITOR) return CommandCost();
1318
1320
1321 return CommandCost(STR_ERROR_CAN_ONLY_BE_POSITIONED);
1322}
1323
1324extern bool _ignore_industry_restrictions;
1325
1332{
1333 if (_game_mode == GM_EDITOR && _ignore_industry_restrictions) return CommandCost();
1334
1335 if (TileHeight(tile) == 0 &&
1337
1338 return CommandCost(STR_ERROR_CAN_ONLY_BE_POSITIONED);
1339}
1340
1347{
1348 if (_settings_game.game_creation.landscape == LandscapeType::Arctic) {
1349 if (GetTileZ(tile) + 2 >= HighestSnowLine()) {
1350 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1351 }
1352 }
1353 return CommandCost();
1354}
1355
1362{
1363 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
1364 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1365 }
1366 return CommandCost();
1367}
1368
1375{
1376 if (GetTropicZone(tile) != TROPICZONE_DESERT) {
1377 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT);
1378 }
1379 return CommandCost();
1380}
1381
1388{
1389 if (GetTropicZone(tile) != TROPICZONE_RAINFOREST) {
1390 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST);
1391 }
1392 return CommandCost();
1393}
1394
1401{
1402 if (GetTileZ(tile) > 4) {
1403 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS);
1404 }
1405 return CommandCost();
1406}
1407
1414
1427
1438static CommandCost FindTownForIndustry(TileIndex tile, IndustryType type, Town **t)
1439{
1440 *t = ClosestTownFromTile(tile, UINT_MAX);
1441
1443
1444 for (const IndustryID &industry : Industry::industries[type]) {
1445 if (Industry::Get(industry)->town == *t) {
1446 *t = nullptr;
1447 return CommandCost(STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN);
1448 }
1449 }
1450
1451 return CommandCost();
1452}
1453
1454bool IsSlopeRefused(Slope current, Slope refused)
1455{
1456 if (IsSteepSlope(current)) return true;
1457 if (current != SLOPE_FLAT) {
1458 if (IsSteepSlope(refused)) return true;
1459
1460 Slope t = ComplementSlope(current);
1461
1462 if ((refused & SLOPE_W) && (t & SLOPE_NW)) return true;
1463 if ((refused & SLOPE_S) && (t & SLOPE_NE)) return true;
1464 if ((refused & SLOPE_E) && (t & SLOPE_SW)) return true;
1465 if ((refused & SLOPE_N) && (t & SLOPE_SE)) return true;
1466 }
1467
1468 return false;
1469}
1470
1478static CommandCost CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTileLayout &layout, IndustryType type)
1479{
1480 IndustryBehaviours ind_behav = GetIndustrySpec(type)->behaviour;
1481
1482 for (const IndustryTileLayoutTile &it : layout) {
1483 IndustryGfx gfx = GetTranslatedIndustryTileID(it.gfx);
1484 TileIndex cur_tile = TileAddWrap(tile, it.ti.x, it.ti.y);
1485
1486 if (!IsValidTile(cur_tile)) {
1487 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1488 }
1489
1490 if (gfx == GFX_WATERTILE_SPECIALCHECK) {
1491 if (!IsWaterTile(cur_tile) ||
1492 !IsTileFlat(cur_tile)) {
1493 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1494 }
1495 } else {
1496 CommandCost ret = EnsureNoVehicleOnGround(cur_tile);
1497 if (ret.Failed()) return ret;
1498 if (IsBridgeAbove(cur_tile)) return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1499
1500 const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
1501
1502 /* Perform land/water check if not disabled */
1503 if (!HasBit(its->slopes_refused, 5) && ((HasTileWaterClass(cur_tile) && IsTileOnWater(cur_tile)) != ind_behav.Test(IndustryBehaviour::BuiltOnWater))) return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1504
1505 if (ind_behav.Any({IndustryBehaviour::OnlyInTown, IndustryBehaviour::Town1200More}) || // Tile must be a house
1506 (ind_behav.Test(IndustryBehaviour::OnlyNearTown) && IsTileType(cur_tile, MP_HOUSE))) { // Tile is allowed to be a house (and it is a house)
1507 if (!IsTileType(cur_tile, MP_HOUSE)) {
1508 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS);
1509 }
1510
1511 /* Clear the tiles as OWNER_TOWN to not affect town rating, and to not clear protected buildings */
1513 ret = Command<CMD_LANDSCAPE_CLEAR>::Do({}, cur_tile);
1514 cur_company.Restore();
1515
1516 if (ret.Failed()) return ret;
1517 } else {
1518 /* Clear the tiles, but do not affect town ratings */
1520 if (ret.Failed()) return ret;
1521 }
1522 }
1523 }
1524
1525 return CommandCost();
1526}
1527
1540static CommandCost CheckIfIndustryTileSlopes(TileIndex tile, const IndustryTileLayout &layout, size_t layout_index, IndustryType type, uint16_t initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type, bool *custom_shape_check = nullptr)
1541{
1542 bool refused_slope = false;
1543 bool custom_shape = false;
1544
1545 for (const IndustryTileLayoutTile &it : layout) {
1546 IndustryGfx gfx = GetTranslatedIndustryTileID(it.gfx);
1547 TileIndex cur_tile = TileAddWrap(tile, it.ti.x, it.ti.y);
1548 assert(IsValidTile(cur_tile)); // checked before in CheckIfIndustryTilesAreFree
1549
1550 if (gfx != GFX_WATERTILE_SPECIALCHECK) {
1551 const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
1552
1554 custom_shape = true;
1555 CommandCost ret = PerformIndustryTileSlopeCheck(tile, cur_tile, its, type, gfx, layout_index, initial_random_bits, founder, creation_type);
1556 if (ret.Failed()) return ret;
1557 } else {
1558 Slope tileh = GetTileSlope(cur_tile);
1559 refused_slope |= IsSlopeRefused(tileh, its->slopes_refused);
1560 }
1561 }
1562 }
1563
1564 if (custom_shape_check != nullptr) *custom_shape_check = custom_shape;
1565
1566 /* It is almost impossible to have a fully flat land in TG, so what we
1567 * do is that we check if we can make the land flat later on. See
1568 * CheckIfCanLevelIndustryPlatform(). */
1569 if (!refused_slope || (_settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world && !custom_shape && !_ignore_industry_restrictions)) {
1570 return CommandCost();
1571 }
1572 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1573}
1574
1582static CommandCost CheckIfIndustryIsAllowed(TileIndex tile, IndustryType type, const Town *t)
1583{
1584 if (GetIndustrySpec(type)->behaviour.Test(IndustryBehaviour::Town1200More) && t->cache.population < 1200) {
1585 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200);
1586 }
1587
1588 if (GetIndustrySpec(type)->behaviour.Test(IndustryBehaviour::OnlyNearTown) && DistanceMax(t->xy, tile) > 9) {
1589 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER);
1590 }
1591
1592 return CommandCost();
1593}
1594
1595static bool CheckCanTerraformSurroundingTiles(TileIndex tile, uint height, int internal)
1596{
1597 /* Check if we don't leave the map */
1598 if (TileX(tile) == 0 || TileY(tile) == 0 || GetTileType(tile) == MP_VOID) return false;
1599
1600 TileArea ta(tile - TileDiffXY(1, 1), 2, 2);
1601 for (TileIndex tile_walk : ta) {
1602 uint curh = TileHeight(tile_walk);
1603 /* Is the tile clear? */
1604 if ((GetTileType(tile_walk) != MP_CLEAR) && (GetTileType(tile_walk) != MP_TREES)) return false;
1605
1606 /* Don't allow too big of a change if this is the sub-tile check */
1607 if (internal != 0 && Delta(curh, height) > 1) return false;
1608
1609 /* Different height, so the surrounding tiles of this tile
1610 * has to be correct too (in level, or almost in level)
1611 * else you get a chain-reaction of terraforming. */
1612 if (internal == 0 && curh != height) {
1613 if (TileX(tile_walk) == 0 || TileY(tile_walk) == 0 || !CheckCanTerraformSurroundingTiles(tile_walk + TileDiffXY(-1, -1), height, internal + 1)) {
1614 return false;
1615 }
1616 }
1617 }
1618
1619 return true;
1620}
1621
1627{
1628 int max_x = 0;
1629 int max_y = 0;
1630
1631 /* Finds dimensions of largest variant of this industry */
1632 for (const IndustryTileLayoutTile &it : layout) {
1633 if (it.gfx == GFX_WATERTILE_SPECIALCHECK) continue; // watercheck tiles don't count for footprint size
1634 if (it.ti.x > max_x) max_x = it.ti.x;
1635 if (it.ti.y > max_y) max_y = it.ti.y;
1636 }
1637
1638 /* Remember level height */
1639 uint h = TileHeight(tile);
1640
1642 /* Check that all tiles in area and surrounding are clear
1643 * this determines that there are no obstructing items */
1644
1645 /* TileArea::Expand is not used here as we need to abort
1646 * instead of clamping if the bounds cannot expanded. */
1649
1650 if (TileX(ta.tile) + ta.w >= Map::MaxX() || TileY(ta.tile) + ta.h >= Map::MaxY()) return false;
1651
1652 /* _current_company is OWNER_NONE for randomly generated industries and in editor, or the company who funded or prospected the industry.
1653 * Perform terraforming as OWNER_TOWN to disable autoslope and town ratings. */
1655
1656 for (TileIndex tile_walk : ta) {
1657 uint curh = TileHeight(tile_walk);
1658 if (curh != h) {
1659 /* This tile needs terraforming. Check if we can do that without
1660 * damaging the surroundings too much. */
1661 if (!CheckCanTerraformSurroundingTiles(tile_walk, h, 0)) {
1662 cur_company.Restore();
1663 return false;
1664 }
1665 /* This is not 100% correct check, but the best we can do without modifying the map.
1666 * What is missing, is if the difference in height is more than 1.. */
1667 if (std::get<0>(Command<CMD_TERRAFORM_LAND>::Do(DoCommandFlags{flags}.Reset(DoCommandFlag::Execute), tile_walk, SLOPE_N, curh <= h)).Failed()) {
1668 cur_company.Restore();
1669 return false;
1670 }
1671 }
1672 }
1673
1674 if (flags.Test(DoCommandFlag::Execute)) {
1675 /* Terraform the land under the industry */
1676 for (TileIndex tile_walk : ta) {
1677 uint curh = TileHeight(tile_walk);
1678 while (curh != h) {
1679 /* We give the terraforming for free here, because we can't calculate
1680 * exact cost in the test-round, and as we all know, that will cause
1681 * a nice assert if they don't match ;) */
1682 Command<CMD_TERRAFORM_LAND>::Do(flags, tile_walk, SLOPE_N, curh <= h);
1683 curh += (curh > h) ? -1 : 1;
1684 }
1685 }
1686 }
1687
1688 cur_company.Restore();
1689 return true;
1690}
1691
1692
1700{
1701 const IndustrySpec *indspec = GetIndustrySpec(type);
1702
1703 for (IndustryType conflicting_type : indspec->conflicting) {
1704 if (conflicting_type == IT_INVALID) continue;
1705
1706 for (const IndustryID &industry : Industry::industries[conflicting_type]) {
1707 /* Within 14 tiles from another industry is considered close */
1708 if (DistanceMax(tile, Industry::Get(industry)->location.tile) > 14) continue;
1709
1710 return CommandCost(STR_ERROR_INDUSTRY_TOO_CLOSE);
1711 }
1712 }
1713 return CommandCost();
1714}
1715
1720static void AdvertiseIndustryOpening(const Industry *ind)
1721{
1722 const IndustrySpec *ind_spc = GetIndustrySpec(ind->type);
1723 EncodedString headline;
1724 if (ind_spc->new_industry_text > STR_LAST_STRINGID) {
1725 headline = GetEncodedString(ind_spc->new_industry_text, ind_spc->name, STR_TOWN_NAME, ind->town->index);
1726 } else {
1727 headline = GetEncodedString(ind_spc->new_industry_text, ind_spc->name, ind->town->index);
1728 }
1729 AddIndustryNewsItem(std::move(headline), NewsType::IndustryOpen, ind->index);
1730 AI::BroadcastNewEvent(new ScriptEventIndustryOpen(ind->index));
1731 Game::NewEvent(new ScriptEventIndustryOpen(ind->index));
1732}
1733
1740{
1742 /* Industry has a neutral station. Use it and ignore any other nearby stations. */
1743 ind->stations_near.insert(ind->neutral_station);
1744 ind->neutral_station->industries_near.clear();
1746 return;
1747 }
1748
1749 ForAllStationsAroundTiles(ind->location, [ind](Station *st, TileIndex tile) {
1750 if (!IsTileType(tile, MP_INDUSTRY) || GetIndustryIndex(tile) != ind->index) return false;
1751 ind->stations_near.insert(st);
1752 st->AddIndustryToDeliver(ind, tile);
1753 return false;
1754 });
1755}
1756
1768static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, const IndustryTileLayout &layout, size_t layout_index, Town *t, Owner founder, uint16_t initial_random_bits)
1769{
1770 const IndustrySpec *indspec = GetIndustrySpec(type);
1771
1772 i->location = TileArea(tile, 1, 1);
1773 i->type = type;
1774
1775 auto &industries = Industry::industries[type];
1776 industries.emplace(std::ranges::lower_bound(industries, i->index), i->index);
1777
1778 for (size_t index = 0; index < std::size(indspec->produced_cargo); ++index) {
1779 if (!IsValidCargoType(indspec->produced_cargo[index])) break;
1780
1781 Industry::ProducedCargo &p = i->produced.emplace_back();
1782 p.cargo = indspec->produced_cargo[index];
1783 p.rate = indspec->production_rate[index];
1784 }
1785
1786 for (size_t index = 0; index < std::size(indspec->accepts_cargo); ++index) {
1787 if (!IsValidCargoType(indspec->accepts_cargo[index])) break;
1788
1789 Industry::AcceptedCargo &a = i->accepted.emplace_back();
1790 a.cargo = indspec->accepts_cargo[index];
1791 }
1792
1793 /* Randomize initial production if non-original economy is used and there are no production related callbacks. */
1794 if (!indspec->UsesOriginalEconomy()) {
1795 for (auto &p : i->produced) {
1796 p.rate = ClampTo<uint8_t>((RandomRange(256) + 128) * p.rate >> 8);
1797 }
1798 }
1799
1800 i->town = t;
1801 i->owner = OWNER_NONE;
1802
1803 uint16_t r = Random();
1804 i->random_colour = static_cast<Colours>(GB(r, 0, 4));
1805 i->counter = GB(r, 4, 12);
1806 i->random = initial_random_bits;
1807 i->was_cargo_delivered = false;
1809 i->founder = founder;
1810 i->ctlflags = {};
1811
1813 i->construction_type = (_game_mode == GM_EDITOR) ? ICT_SCENARIO_EDITOR :
1815
1816 /* Adding 1 here makes it conform to specs of var44 of varaction2 for industries
1817 * 0 = created prior of newindustries
1818 * else, chosen layout + 1 */
1819 i->selected_layout = (uint8_t)(layout_index + 1);
1820
1823
1825
1826 /* Call callbacks after the regular fields got initialised. */
1827
1830 if (res != CALLBACK_FAILED) {
1831 if (res < PRODLEVEL_MINIMUM || res > PRODLEVEL_MAXIMUM) {
1833 } else {
1834 i->prod_level = res;
1836 }
1837 }
1838 }
1839
1840 if (_generating_world) {
1843 for (auto &p : i->produced) {
1844 p.history[LAST_MONTH].production = ScaleByCargoScale(p.waiting * 8, false);
1845 p.waiting = 0;
1846 }
1847 }
1848
1849 for (auto &p : i->produced) {
1850 p.history[LAST_MONTH].production += ScaleByCargoScale(p.rate * 8, false);
1851 }
1852 }
1853
1855 uint16_t res = GetIndustryCallback(CBID_INDUSTRY_DECIDE_COLOUR, 0, 0, i, type, INVALID_TILE);
1856 if (res != CALLBACK_FAILED) {
1857 if (GB(res, 4, 11) != 0) ErrorUnknownCallbackResult(indspec->grf_prop.grfid, CBID_INDUSTRY_DECIDE_COLOUR, res);
1858 i->random_colour = static_cast<Colours>(GB(res, 0, 4));
1859 }
1860 }
1861
1863 /* Clear all input cargo types */
1864 i->accepted.clear();
1865 /* Query actual types */
1867 for (uint j = 0; j < maxcargoes; j++) {
1869 if (res == CALLBACK_FAILED || GB(res, 0, 8) == UINT8_MAX) break;
1870 if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
1872 break;
1873 }
1874 CargoType cargo = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
1875 /* Industries without "unlimited" cargo types support depend on the specific order/slots of cargo types.
1876 * They need to be able to blank out specific slots without aborting the callback sequence,
1877 * and solve this by returning undefined cargo indexes. Skip these. */
1879 /* As slots are allocated as needed now, this means we do need to add a slot for the invalid cargo. */
1880 Industry::AcceptedCargo &a = i->accepted.emplace_back();
1881 a.cargo = INVALID_CARGO;
1882 continue;
1883 }
1884 /* Verify valid cargo */
1885 if (std::ranges::find(indspec->accepts_cargo, cargo) == std::end(indspec->accepts_cargo)) {
1886 /* Cargo not in spec, error in NewGRF */
1888 break;
1889 }
1890 if (std::any_of(std::begin(i->accepted), std::begin(i->accepted) + j, [&cargo](const auto &a) { return a.cargo == cargo; })) {
1891 /* Duplicate cargo */
1893 break;
1894 }
1895 Industry::AcceptedCargo &a = i->accepted.emplace_back();
1896 a.cargo = cargo;
1897 }
1898 }
1899
1901 /* Clear all output cargo types */
1902 i->produced.clear();
1903 /* Query actual types */
1905 for (uint j = 0; j < maxcargoes; j++) {
1907 if (res == CALLBACK_FAILED || GB(res, 0, 8) == UINT8_MAX) break;
1908 if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
1910 break;
1911 }
1912 CargoType cargo = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
1913 /* Allow older GRFs to skip slots. */
1915 /* As slots are allocated as needed now, this means we do need to add a slot for the invalid cargo. */
1916 Industry::ProducedCargo &p = i->produced.emplace_back();
1917 p.cargo = INVALID_CARGO;
1918 continue;
1919 }
1920 /* Verify valid cargo */
1921 if (std::ranges::find(indspec->produced_cargo, cargo) == std::end(indspec->produced_cargo)) {
1922 /* Cargo not in spec, error in NewGRF */
1924 break;
1925 }
1926 if (std::any_of(std::begin(i->produced), std::begin(i->produced) + j, [&cargo](const auto &p) { return p.cargo == cargo; })) {
1927 /* Duplicate cargo */
1929 break;
1930 }
1931 Industry::ProducedCargo &p = i->produced.emplace_back();
1932 p.cargo = cargo;
1933 }
1934 }
1935
1936 /* Plant the tiles */
1937
1938 for (const IndustryTileLayoutTile &it : layout) {
1939 TileIndex cur_tile = tile + ToTileIndexDiff(it.ti);
1940
1941 if (it.gfx != GFX_WATERTILE_SPECIALCHECK) {
1942 i->location.Add(cur_tile);
1943
1944 WaterClass wc = (IsWaterTile(cur_tile) ? GetWaterClass(cur_tile) : WATER_CLASS_INVALID);
1945
1947
1948 MakeIndustry(cur_tile, i->index, it.gfx, Random(), wc);
1949
1950 if (_generating_world) {
1951 SetIndustryConstructionCounter(cur_tile, 3);
1952 SetIndustryConstructionStage(cur_tile, 2);
1953 }
1954
1955 /* it->gfx is stored in the map. But the translated ID cur_gfx is the interesting one */
1956 IndustryGfx cur_gfx = GetTranslatedIndustryTileID(it.gfx);
1957 const IndustryTileSpec *its = GetIndustryTileSpec(cur_gfx);
1959 }
1960 }
1961
1963 for (uint j = 0; j != 50; j++) PlantRandomFarmField(i);
1964 }
1965 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, IDIWD_FORCE_REBUILD);
1967
1969}
1970
1987static CommandCost CreateNewIndustryHelper(TileIndex tile, IndustryType type, DoCommandFlags flags, const IndustrySpec *indspec, size_t layout_index, uint32_t random_var8f, uint16_t random_initial_bits, Owner founder, IndustryAvailabilityCallType creation_type, Industry **ip)
1988{
1989 assert(layout_index < indspec->layouts.size());
1990 const IndustryTileLayout &layout = indspec->layouts[layout_index];
1991
1992 *ip = nullptr;
1993
1994 /* 1. Cheap: Built-in checks on industry level. */
1996 if (ret.Failed()) return ret;
1997
1998 Town *t = nullptr;
1999 ret = FindTownForIndustry(tile, type, &t);
2000 if (ret.Failed()) return ret;
2001 assert(t != nullptr);
2002
2003 ret = CheckIfIndustryIsAllowed(tile, type, t);
2004 if (ret.Failed()) return ret;
2005
2006 /* 2. Built-in checks on industry tiles. */
2007 std::vector<ClearedObjectArea> object_areas(_cleared_object_areas);
2008 ret = CheckIfIndustryTilesAreFree(tile, layout, type);
2009 _cleared_object_areas = std::move(object_areas);
2010 if (ret.Failed()) return ret;
2011
2012 /* 3. NewGRF-defined checks on industry level. */
2013 if (GetIndustrySpec(type)->callback_mask.Test(IndustryCallbackMask::Location)) {
2014 ret = CheckIfCallBackAllowsCreation(tile, type, layout_index, random_var8f, random_initial_bits, founder, creation_type);
2015 } else {
2016 ret = _check_new_industry_procs[indspec->check_proc](tile);
2017 }
2018 if (ret.Failed()) return ret;
2019
2020 /* 4. Expensive: NewGRF-defined checks on industry tiles. */
2021 bool custom_shape_check = false;
2022 ret = CheckIfIndustryTileSlopes(tile, layout, layout_index, type, random_initial_bits, founder, creation_type, &custom_shape_check);
2023 if (ret.Failed()) return ret;
2024
2026 !_ignore_industry_restrictions && !CheckIfCanLevelIndustryPlatform(tile, DoCommandFlag::NoWater, layout)) {
2027 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
2028 }
2029
2030 if (!Industry::CanAllocateItem()) return CommandCost(STR_ERROR_TOO_MANY_INDUSTRIES);
2031
2032 if (flags.Test(DoCommandFlag::Execute)) {
2033 *ip = new Industry(tile);
2034 if (!custom_shape_check) CheckIfCanLevelIndustryPlatform(tile, {DoCommandFlag::NoWater, DoCommandFlag::Execute}, layout);
2035 DoCreateNewIndustry(*ip, tile, type, layout, layout_index, t, founder, random_initial_bits);
2036 }
2037
2038 return CommandCost();
2039}
2040
2051CommandCost CmdBuildIndustry(DoCommandFlags flags, TileIndex tile, IndustryType it, uint32_t first_layout, bool fund, uint32_t seed)
2052{
2053 if (it >= NUM_INDUSTRYTYPES) return CMD_ERROR;
2054
2055 const IndustrySpec *indspec = GetIndustrySpec(it);
2056
2057 /* Check if the to-be built/founded industry is available for this climate. */
2058 if (!indspec->enabled || indspec->layouts.empty()) return CMD_ERROR;
2059
2060 /* If the setting for raw-material industries is not on, you cannot build raw-material industries.
2061 * Raw material industries are industries that do not accept cargo (at least for now) */
2062 if (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 0 && indspec->IsRawIndustry()) {
2063 return CMD_ERROR;
2064 }
2065
2066 if (_game_mode != GM_EDITOR && GetIndustryProbabilityCallback(it, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, 1) == 0) {
2067 return CMD_ERROR;
2068 }
2069
2070 Randomizer randomizer;
2071 randomizer.SetSeed(seed);
2072 uint16_t random_initial_bits = GB(seed, 0, 16);
2073 uint32_t random_var8f = randomizer.Next();
2074 size_t num_layouts = indspec->layouts.size();
2075 CommandCost ret = CommandCost(STR_ERROR_SITE_UNSUITABLE);
2076 const bool deity_prospect = _current_company == OWNER_DEITY && !fund;
2077
2078 Industry *ind = nullptr;
2079 if (deity_prospect || (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 2 && indspec->IsRawIndustry())) {
2080 if (flags.Test(DoCommandFlag::Execute)) {
2081 /* Prospecting has a chance to fail, however we cannot guarantee that something can
2082 * be built on the map, so the chance gets lower when the map is fuller, but there
2083 * is nothing we can really do about that. */
2084 bool prospect_success = deity_prospect || Random() <= indspec->prospecting_chance;
2085 if (prospect_success) {
2086 /* Prospected industries are build as OWNER_TOWN to not e.g. be build on owned land of the founder */
2089 for (int i = 0; i < 5000; i++) {
2090 /* We should not have more than one Random() in a function call
2091 * because parameter evaluation order is not guaranteed in the c++ standard
2092 */
2093 tile = RandomTile();
2094 /* Start with a random layout */
2095 size_t layout = RandomRange((uint32_t)num_layouts);
2096 /* Check now each layout, starting with the random one */
2097 for (size_t j = 0; j < num_layouts; j++) {
2098 layout = (layout + 1) % num_layouts;
2099 ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, cur_company.GetOriginalValue(), calltype, &ind);
2100 if (ret.Succeeded()) break;
2101 }
2102 if (ret.Succeeded()) break;
2103 }
2104 cur_company.Restore();
2105 }
2106 if (ret.Failed() && IsLocalCompany()) {
2107 if (prospect_success) {
2108 ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_PROSPECT_INDUSTRY), GetEncodedString(STR_ERROR_NO_SUITABLE_PLACES_FOR_PROSPECTING), WL_INFO);
2109 } else {
2110 ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_PROSPECT_INDUSTRY), GetEncodedString(STR_ERROR_PROSPECTING_WAS_UNLUCKY), WL_INFO);
2111 }
2112 }
2113 }
2114 } else {
2115 size_t layout = first_layout;
2116 if (layout >= num_layouts) return CMD_ERROR;
2117
2118 /* Check subsequently each layout, starting with the given layout in p1 */
2119 for (size_t i = 0; i < num_layouts; i++) {
2120 layout = (layout + 1) % num_layouts;
2121 ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, _current_company, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, &ind);
2122 if (ret.Succeeded()) break;
2123 }
2124
2125 /* If it still failed, there's no suitable layout to build here, return the error */
2126 if (ret.Failed()) return ret;
2127 }
2128
2129 if (flags.Test(DoCommandFlag::Execute) && ind != nullptr && _game_mode != GM_EDITOR) {
2131 }
2132
2134}
2135
2144{
2145 if (_current_company != OWNER_DEITY) return CMD_ERROR;
2146
2147 Industry *ind = Industry::GetIfValid(ind_id);
2148 if (ind == nullptr) return CMD_ERROR;
2149 if (!ctlflags.IsValid()) return CMD_ERROR;
2150
2151 if (flags.Test(DoCommandFlag::Execute)) ind->ctlflags = ctlflags;
2152
2153 return CommandCost();
2154}
2155
2165CommandCost CmdIndustrySetProduction(DoCommandFlags flags, IndustryID ind_id, uint8_t prod_level, bool show_news, const EncodedString &custom_news)
2166{
2167 if (_current_company != OWNER_DEITY) return CMD_ERROR;
2168 if (prod_level < PRODLEVEL_MINIMUM || prod_level > PRODLEVEL_MAXIMUM) return CMD_ERROR;
2169
2170 Industry *ind = Industry::GetIfValid(ind_id);
2171 if (ind == nullptr) return CMD_ERROR;
2172
2173 if (flags.Test(DoCommandFlag::Execute)) {
2175 ind->prod_level = prod_level;
2177
2178 /* Show news message if requested. */
2179 if (show_news && prod_level != ind->prod_level) {
2180 NewsType nt;
2181 switch (WhoCanServiceIndustry(ind)) {
2182 case 0: nt = NewsType::IndustryNobody; break;
2183 case 1: nt = NewsType::IndustryOther; break;
2184 case 2: nt = NewsType::IndustryCompany; break;
2185 default: NOT_REACHED();
2186 }
2187
2188 /* Set parameters of news string */
2189 EncodedString headline;
2190 if (!custom_news.empty()) {
2191 headline = custom_news;
2192 } else {
2193 StringID str = (prod_level > ind->prod_level)
2196
2197 if (str > STR_LAST_STRINGID) {
2198 headline = GetEncodedString(str, STR_TOWN_NAME, ind->town->index, GetIndustrySpec(ind->type)->name);
2199 } else {
2200 headline = GetEncodedString(str, ind->index);
2201 }
2202 }
2203
2204 AddIndustryNewsItem(std::move(headline), nt, ind->index);
2205 }
2206 }
2207
2208 return CommandCost();
2209}
2210
2221{
2222 if (_current_company != OWNER_DEITY) return CMD_ERROR;
2223
2224 Industry *ind = Industry::GetIfValid(ind_id);
2225 if (ind == nullptr) return CMD_ERROR;
2226
2227 if (company_id != OWNER_NONE && company_id != INVALID_OWNER && company_id != OWNER_DEITY
2228 && !Company::IsValidID(company_id)) return CMD_ERROR;
2229
2230 if (flags.Test(DoCommandFlag::Execute)) {
2231 if (consumer) {
2232 ind->exclusive_consumer = company_id;
2233 } else {
2234 ind->exclusive_supplier = company_id;
2235 }
2236 }
2237
2238
2239 return CommandCost();
2240}
2241
2250{
2251 if (_current_company != OWNER_DEITY) return CMD_ERROR;
2252
2253 Industry *ind = Industry::GetIfValid(ind_id);
2254 if (ind == nullptr) return CMD_ERROR;
2255
2256 if (flags.Test(DoCommandFlag::Execute)) {
2257 ind->text.clear();
2258 if (!text.empty()) ind->text = text;
2260 }
2261
2262 return CommandCost();
2263}
2264
2272static Industry *CreateNewIndustry(TileIndex tile, IndustryType type, IndustryAvailabilityCallType creation_type)
2273{
2274 const IndustrySpec *indspec = GetIndustrySpec(type);
2275
2276 uint32_t seed = Random();
2277 uint32_t seed2 = Random();
2278 Industry *i = nullptr;
2279 size_t layout_index = RandomRange((uint32_t)indspec->layouts.size());
2280 [[maybe_unused]] CommandCost ret = CreateNewIndustryHelper(tile, type, DoCommandFlag::Execute, indspec, layout_index, seed, GB(seed2, 0, 16), OWNER_NONE, creation_type, &i);
2281 assert(i != nullptr || ret.Failed());
2282 return i;
2283}
2284
2291static uint32_t GetScaledIndustryGenerationProbability(IndustryType it, bool *force_at_least_one)
2292{
2293 const IndustrySpec *ind_spc = GetIndustrySpec(it);
2295 if (!ind_spc->enabled || ind_spc->layouts.empty() ||
2296 (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == ID_FUND_ONLY) ||
2297 (chance = GetIndustryProbabilityCallback(it, IACT_MAPGENERATION, chance)) == 0) {
2298 *force_at_least_one = false;
2299 return 0;
2300 } else {
2301 chance *= 16; // to increase precision
2302 /* We want industries appearing at coast to appear less often on bigger maps, as length of coast increases slower than map area.
2303 * For simplicity we scale in both cases, though scaling the probabilities of all industries has no effect. */
2304 chance = (ind_spc->check_proc == CHECK_REFINERY || ind_spc->check_proc == CHECK_OIL_RIG) ? Map::ScaleBySize1D(chance) : Map::ScaleBySize(chance);
2305
2306 *force_at_least_one = (chance > 0) && !ind_spc->behaviour.Test(IndustryBehaviour::NoBuildMapCreation) && (_game_mode != GM_EDITOR);
2307 return chance;
2308 }
2309}
2310
2317static uint16_t GetIndustryGamePlayProbability(IndustryType it, uint8_t *min_number)
2318{
2320 *min_number = 0;
2321 return 0;
2322 }
2323
2324 const IndustrySpec *ind_spc = GetIndustrySpec(it);
2326 if (!ind_spc->enabled || ind_spc->layouts.empty() ||
2329 (chance = GetIndustryProbabilityCallback(it, IACT_RANDOMCREATION, chance)) == 0) {
2330 *min_number = 0;
2331 return 0;
2332 }
2333 *min_number = ind_spc->behaviour.Test(IndustryBehaviour::CanCloseLastInstance) ? 1 : 0;
2334 return chance;
2335}
2336
2342{
2343 /* Number of industries on a 256x256 map. */
2344 static const uint16_t numof_industry_table[] = {
2345 0, // none
2346 0, // minimal
2347 10, // very low
2348 25, // low
2349 55, // normal
2350 80, // high
2351 0, // custom
2352 };
2353
2354 assert(lengthof(numof_industry_table) == ID_END);
2355 uint difficulty = (_game_mode != GM_EDITOR) ? _settings_game.difficulty.industry_density : (uint)ID_VERY_LOW;
2356
2357 if (difficulty == ID_CUSTOM) return std::min<uint>(IndustryPool::MAX_SIZE, _settings_game.game_creation.custom_industry_number);
2358
2359 return std::min<uint>(IndustryPool::MAX_SIZE, Map::ScaleBySize(numof_industry_table[difficulty]));
2360}
2361
2370static Industry *PlaceIndustry(IndustryType type, IndustryAvailabilityCallType creation_type, bool try_hard)
2371{
2372 uint tries = try_hard ? 10000u : 2000u;
2373 for (; tries > 0; tries--) {
2374 Industry *ind = CreateNewIndustry(RandomTile(), type, creation_type);
2375 if (ind != nullptr) return ind;
2376 }
2377 return nullptr;
2378}
2379
2385static void PlaceInitialIndustry(IndustryType type, bool try_hard)
2386{
2388
2390 PlaceIndustry(type, IACT_MAPGENERATION, try_hard);
2391
2392 cur_company.Restore();
2393}
2394
2400{
2401 uint total = 0;
2402 for (const auto &industries : Industry::industries) {
2403 total += static_cast<uint16_t>(std::size(industries));
2404 }
2405 return total;
2406}
2407
2408
2411{
2412 this->probability = 0;
2413 this->min_number = 0;
2414 this->target_count = 0;
2415 this->max_wait = 1;
2416 this->wait_count = 0;
2417}
2418
2421{
2423
2424 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2425 this->builddata[it].Reset();
2426 }
2427}
2428
2431{
2432 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.
2433 if (_settings_game.difficulty.industry_density == ID_FUND_ONLY) return; // 'no industries' setting.
2434
2435 /* To prevent running out of unused industries for the player to connect,
2436 * add a fraction of new industries each month, but only if the manager can keep up. */
2437 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).
2438 if (GetCurrentTotalNumberOfIndustries() + max_behind >= (this->wanted_inds >> 16)) {
2439 this->wanted_inds += Map::ScaleBySize(NEWINDS_PER_MONTH);
2440 }
2441}
2442
2448{
2449 if (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == ID_FUND_ONLY) return; // No industries in the game.
2450
2451 uint32_t industry_probs[NUM_INDUSTRYTYPES];
2452 bool force_at_least_one[NUM_INDUSTRYTYPES];
2453 uint32_t total_prob = 0;
2454 uint num_forced = 0;
2455
2456 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2457 industry_probs[it] = GetScaledIndustryGenerationProbability(it, force_at_least_one + it);
2458 total_prob += industry_probs[it];
2459 if (force_at_least_one[it]) num_forced++;
2460 }
2461
2462 uint total_amount = GetNumberOfIndustries();
2463 if (total_prob == 0 || total_amount < num_forced) {
2464 /* Only place the forced ones */
2465 total_amount = num_forced;
2466 }
2467
2469
2470 /* Try to build one industry per type independent of any probabilities */
2471 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2472 if (force_at_least_one[it]) {
2473 assert(total_amount > 0);
2474 total_amount--;
2475 PlaceInitialIndustry(it, true);
2476 }
2477 }
2478
2479 /* Add the remaining industries according to their probabilities */
2480 for (uint i = 0; i < total_amount; i++) {
2481 uint32_t r = RandomRange(total_prob);
2482 IndustryType it = 0;
2483 while (r >= industry_probs[it]) {
2484 r -= industry_probs[it];
2485 it++;
2486 assert(it < NUM_INDUSTRYTYPES);
2487 }
2488 assert(industry_probs[it] > 0);
2489 PlaceInitialIndustry(it, false);
2490 }
2492}
2493
2499{
2500 for (auto &p : i->produced) {
2501 if (IsValidCargoType(p.cargo)) {
2502 if (p.history[THIS_MONTH].production != 0) i->last_prod_year = TimerGameEconomy::year;
2503
2504 /* Move history from this month to last month. */
2505 std::rotate(std::rbegin(p.history), std::rbegin(p.history) + 1, std::rend(p.history));
2506 p.history[THIS_MONTH].production = 0;
2507 p.history[THIS_MONTH].transported = 0;
2508 }
2509 }
2510}
2511
2517{
2518 const IndustrySpec *indspec = GetIndustrySpec(this->type);
2519 assert(indspec->UsesOriginalEconomy());
2520
2521 /* Rates are rounded up, so e.g. oilrig always produces some passengers */
2522 for (auto &p : this->produced) {
2523 p.rate = ClampTo<uint8_t>(CeilDiv(indspec->production_rate[&p - this->produced.data()] * this->prod_level, PRODLEVEL_DEFAULT));
2524 }
2525}
2526
2527void Industry::FillCachedName() const
2528{
2529 auto tmp_params = MakeParameters(this->index);
2530 this->cached_name = GetStringWithArgs(STR_INDUSTRY_NAME, tmp_params);
2531}
2532
2533void ClearAllIndustryCachedNames()
2534{
2535 for (Industry *ind : Industry::Iterate()) {
2536 ind->cached_name.clear();
2537 }
2538}
2539
2546{
2547 uint8_t min_number;
2549 bool changed = min_number != this->min_number || probability != this->probability;
2550 this->min_number = min_number;
2551 this->probability = probability;
2552 return changed;
2553}
2554
2557{
2558 bool changed = false;
2559 uint num_planned = 0; // Number of industries planned in the industry build data.
2560 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2561 changed |= this->builddata[it].GetIndustryTypeData(it);
2562 num_planned += this->builddata[it].target_count;
2563 }
2564 uint total_amount = this->wanted_inds >> 16; // Desired total number of industries.
2565 changed |= num_planned != total_amount;
2566 if (!changed) return; // All industries are still the same, no need to re-randomize.
2567
2568 /* Initialize the target counts. */
2569 uint force_build = 0; // Number of industries that should always be available.
2570 uint32_t total_prob = 0; // Sum of probabilities.
2571 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2572 IndustryTypeBuildData *ibd = this->builddata + it;
2573 force_build += ibd->min_number;
2574 ibd->target_count = ibd->min_number;
2575 total_prob += ibd->probability;
2576 }
2577
2578 if (total_prob == 0) return; // No buildable industries.
2579
2580 /* Subtract forced industries from the number of industries available for construction. */
2581 total_amount = (total_amount <= force_build) ? 0 : total_amount - force_build;
2582
2583 /* Assign number of industries that should be aimed for, by using the probability as a weight. */
2584 while (total_amount > 0) {
2585 uint32_t r = RandomRange(total_prob);
2586 IndustryType it = 0;
2587 while (r >= this->builddata[it].probability) {
2588 r -= this->builddata[it].probability;
2589 it++;
2590 assert(it < NUM_INDUSTRYTYPES);
2591 }
2592 assert(this->builddata[it].probability > 0);
2593 this->builddata[it].target_count++;
2594 total_amount--;
2595 }
2596}
2597
2602{
2603 this->SetupTargetCount();
2604
2605 int missing = 0; // Number of industries that need to be build.
2606 uint count = 0; // Number of industry types eligible for build.
2607 uint32_t total_prob = 0; // Sum of probabilities.
2608 IndustryType forced_build = NUM_INDUSTRYTYPES; // Industry type that should be forcibly build.
2609 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2610 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
2611 missing += difference;
2612 if (this->builddata[it].wait_count > 0) continue; // This type may not be built now.
2613 if (difference > 0) {
2614 if (Industry::GetIndustryTypeCount(it) == 0 && this->builddata[it].min_number > 0) {
2615 /* An industry that should exist at least once, is not available. Force it, trying the most needed one first. */
2616 if (forced_build == NUM_INDUSTRYTYPES ||
2617 difference > this->builddata[forced_build].target_count - Industry::GetIndustryTypeCount(forced_build)) {
2618 forced_build = it;
2619 }
2620 }
2621 total_prob += difference;
2622 count++;
2623 }
2624 }
2625
2626 if (EconomyIsInRecession() || (forced_build == NUM_INDUSTRYTYPES && (missing <= 0 || total_prob == 0))) count = 0; // Skip creation of an industry.
2627
2628 if (count >= 1) {
2629 /* If not forced, pick a weighted random industry to build.
2630 * For the case that count == 1, there is no need to draw a random number. */
2631 IndustryType it;
2632 if (forced_build != NUM_INDUSTRYTYPES) {
2633 it = forced_build;
2634 } else {
2635 /* Non-forced, select an industry type to build (weighted random). */
2636 uint32_t r = 0; // Initialized to silence the compiler.
2637 if (count > 1) r = RandomRange(total_prob);
2638 for (it = 0; it < NUM_INDUSTRYTYPES; it++) {
2639 if (this->builddata[it].wait_count > 0) continue; // Type may not be built now.
2640 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
2641 if (difference <= 0) continue; // Too many of this kind.
2642 if (count == 1) break;
2643 if (r < (uint)difference) break;
2644 r -= difference;
2645 }
2646 assert(it < NUM_INDUSTRYTYPES && this->builddata[it].target_count > Industry::GetIndustryTypeCount(it));
2647 }
2648
2649 /* Try to create the industry. */
2650 const Industry *ind = PlaceIndustry(it, IACT_RANDOMCREATION, false);
2651 if (ind == nullptr) {
2652 this->builddata[it].wait_count = this->builddata[it].max_wait + 1; // Compensate for decrementing below.
2653 this->builddata[it].max_wait = std::min(1000, this->builddata[it].max_wait + 2);
2654 } else {
2656 this->builddata[it].max_wait = std::max(this->builddata[it].max_wait / 2, 1); // Reduce waiting time of the industry type.
2657 }
2658 }
2659
2660 /* Decrement wait counters. */
2661 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2662 if (this->builddata[it].wait_count > 0) this->builddata[it].wait_count--;
2663 }
2664}
2665
2674static bool CheckIndustryCloseDownProtection(IndustryType type)
2675{
2676 const IndustrySpec *indspec = GetIndustrySpec(type);
2677
2678 /* oil wells (or the industries with that flag set) are always allowed to closedown */
2679 if (indspec->behaviour.Test(IndustryBehaviour::DontIncrProd) && _settings_game.game_creation.landscape == LandscapeType::Temperate) return false;
2681}
2682
2692static void CanCargoServiceIndustry(CargoType cargo, Industry *ind, bool *c_accepts, bool *c_produces)
2693{
2694 if (!IsValidCargoType(cargo)) return;
2695
2696 /* Check for acceptance of cargo */
2697 if (ind->IsCargoAccepted(cargo) && !IndustryTemporarilyRefusesCargo(ind, cargo)) *c_accepts = true;
2698
2699 /* Check for produced cargo */
2700 if (ind->IsCargoProduced(cargo)) *c_produces = true;
2701}
2702
2717{
2718 if (ind->stations_near.empty()) return 0; // No stations found at all => nobody services
2719
2720 int result = 0;
2721 for (const Vehicle *v : Vehicle::Iterate()) {
2722 /* Is it worthwhile to try this vehicle? */
2723 if (v->owner != _local_company && result != 0) continue;
2724
2725 /* Check whether it accepts the right kind of cargo */
2726 bool c_accepts = false;
2727 bool c_produces = false;
2728 if (v->type == VEH_TRAIN && v->IsFrontEngine()) {
2729 for (const Vehicle *u = v; u != nullptr; u = u->Next()) {
2730 CanCargoServiceIndustry(u->cargo_type, ind, &c_accepts, &c_produces);
2731 }
2732 } else if (v->type == VEH_ROAD || v->type == VEH_SHIP || v->type == VEH_AIRCRAFT) {
2733 CanCargoServiceIndustry(v->cargo_type, ind, &c_accepts, &c_produces);
2734 } else {
2735 continue;
2736 }
2737 if (!c_accepts && !c_produces) continue; // Wrong cargo
2738
2739 /* Check orders of the vehicle.
2740 * We cannot check the first of shared orders only, since the first vehicle in such a chain
2741 * may have a different cargo type.
2742 */
2743 for (const Order *o : v->Orders()) {
2744 if (o->IsType(OT_GOTO_STATION) && !(o->GetUnloadType() & OUFB_TRANSFER)) {
2745 /* Vehicle visits a station to load or unload */
2746 Station *st = Station::Get(o->GetDestination().ToStationID());
2747 assert(st != nullptr);
2748
2749 /* Same cargo produced by industry is dropped here => not serviced by vehicle v */
2750 if ((o->GetUnloadType() & OUFB_UNLOAD) && !c_accepts) break;
2751
2752 if (ind->stations_near.find(st) != ind->stations_near.end()) {
2753 if (v->owner == _local_company) return 2; // Company services industry
2754 result = 1; // Competitor services industry
2755 }
2756 }
2757 }
2758 }
2759 return result;
2760}
2761
2769static void ReportNewsProductionChangeIndustry(Industry *ind, CargoType cargo, int percent)
2770{
2771 NewsType nt;
2772
2773 switch (WhoCanServiceIndustry(ind)) {
2774 case 0: nt = NewsType::IndustryNobody; break;
2775 case 1: nt = NewsType::IndustryOther; break;
2776 case 2: nt = NewsType::IndustryCompany; break;
2777 default: NOT_REACHED();
2778 }
2779 AddIndustryNewsItem(
2780 GetEncodedString(percent >= 0 ? STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH : STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH,
2781 CargoSpec::Get(cargo)->name, ind->index, abs(percent)
2782 ),
2783 nt,
2784 ind->index
2785 );
2786}
2787
2788static const uint PERCENT_TRANSPORTED_60 = 153;
2789static const uint PERCENT_TRANSPORTED_80 = 204;
2790
2796static void ChangeIndustryProduction(Industry *i, bool monthly)
2797{
2798 StringID str = STR_NULL;
2799 bool closeit = false;
2800 const IndustrySpec *indspec = GetIndustrySpec(i->type);
2801 bool standard = false;
2802 bool suppress_message = false;
2803 bool recalculate_multipliers = false;
2804 /* use original economy for industries using production related callbacks */
2805 bool original_economy = indspec->UsesOriginalEconomy();
2806 uint8_t div = 0;
2807 uint8_t mul = 0;
2808 int8_t increment = 0;
2809
2811 if (callback_enabled) {
2812 uint16_t res = GetIndustryCallback(monthly ? CBID_INDUSTRY_MONTHLYPROD_CHANGE : CBID_INDUSTRY_PRODUCTION_CHANGE, 0, Random(), i, i->type, i->location.tile);
2813 if (res != CALLBACK_FAILED) { // failed callback means "do nothing"
2814 suppress_message = HasBit(res, 7);
2815 /* Get the custom message if any */
2816 if (HasBit(res, 8)) str = MapGRFStringID(indspec->grf_prop.grfid, GRFStringID(GB(GetRegister(0x100), 0, 16)));
2817 res = GB(res, 0, 4);
2818 switch (res) {
2819 default: NOT_REACHED();
2820 case 0x0: break; // Do nothing, but show the custom message if any
2821 case 0x1: div = 1; break; // Halve industry production. If production reaches the quarter of the default, the industry is closed instead.
2822 case 0x2: mul = 1; break; // Double industry production if it hasn't reached eight times of the original yet.
2823 case 0x3: closeit = true; break; // The industry announces imminent closure, and is physically removed from the map next month.
2824 case 0x4: standard = true; break; // Do the standard random production change as if this industry was a primary one.
2825 case 0x5: case 0x6: case 0x7: // Divide production by 4, 8, 16
2826 case 0x8: div = res - 0x3; break; // Divide production by 32
2827 case 0x9: case 0xA: case 0xB: // Multiply production by 4, 8, 16
2828 case 0xC: mul = res - 0x7; break; // Multiply production by 32
2829 case 0xD: // decrement production
2830 case 0xE: // increment production
2831 increment = res == 0x0D ? -1 : 1;
2832 break;
2833 case 0xF: // Set production to third byte of register 0x100
2834 i->prod_level = Clamp(GB(GetRegister(0x100), 16, 8), PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
2835 recalculate_multipliers = true;
2836 break;
2837 }
2838 }
2839 } else {
2840 if (monthly == original_economy) return;
2841 if (!original_economy && _settings_game.economy.type == ET_FROZEN) return;
2842 if (indspec->life_type == INDUSTRYLIFE_BLACK_HOLE) return;
2843 }
2844
2845 if (standard || (!callback_enabled && indspec->life_type.Any({IndustryLifeType::Organic, IndustryLifeType::Extractive}))) {
2846 /* decrease or increase */
2847 bool only_decrease = indspec->behaviour.Test(IndustryBehaviour::DontIncrProd) && _settings_game.game_creation.landscape == LandscapeType::Temperate;
2848
2849 if (original_economy) {
2850 if (only_decrease || Chance16(1, 3)) {
2851 /* If more than 60% transported, 66% chance of increase, else 33% chance of increase */
2852 if (!only_decrease && (i->GetProduced(0).history[LAST_MONTH].PctTransported() > PERCENT_TRANSPORTED_60) != Chance16(1, 3)) {
2853 mul = 1; // Increase production
2854 } else {
2855 div = 1; // Decrease production
2856 }
2857 }
2858 } else if (_settings_game.economy.type == ET_SMOOTH) {
2860 for (auto &p : i->produced) {
2861 if (!IsValidCargoType(p.cargo)) continue;
2862 uint32_t r = Random();
2863 int old_prod, new_prod, percent;
2864 /* If over 60% is transported, mult is 1, else mult is -1. */
2865 int mult = (p.history[LAST_MONTH].PctTransported() > PERCENT_TRANSPORTED_60) ? 1 : -1;
2866
2867 new_prod = old_prod = p.rate;
2868
2869 /* For industries with only_decrease flags (temperate terrain Oil Wells),
2870 * the multiplier will always be -1 so they will only decrease. */
2871 if (only_decrease) {
2872 mult = -1;
2873 /* For normal industries, if over 60% is transported, 33% chance for decrease.
2874 * Bonus for very high station ratings (over 80%): 16% chance for decrease. */
2875 } else if (Chance16I(1, ((p.history[LAST_MONTH].PctTransported() > PERCENT_TRANSPORTED_80) ? 6 : 3), r)) {
2876 mult *= -1;
2877 }
2878
2879 /* 4.5% chance for 3-23% (or 1 unit for very low productions) production change,
2880 * determined by mult value. If mult = 1 prod. increases, else (-1) it decreases. */
2881 if (Chance16I(1, 22, r >> 16)) {
2882 new_prod += mult * (std::max(((RandomRange(50) + 10) * old_prod) >> 8, 1U));
2883 }
2884
2885 /* Prevent production to overflow or Oil Rig passengers to be over-"produced" */
2886 new_prod = Clamp(new_prod, 1, 255);
2887 if (IsValidCargoType(p.cargo) && p.cargo == GetCargoTypeByLabel(CT_PASSENGERS) && !indspec->behaviour.Test(IndustryBehaviour::NoPaxProdClamp)) {
2888 new_prod = Clamp(new_prod, 0, 16);
2889 }
2890
2891 /* If override flags are set, prevent actually changing production if any was decided on */
2892 if (i->ctlflags.Test(IndustryControlFlag::NoProductionDecrease) && new_prod < old_prod) continue;
2893 if (i->ctlflags.Test(IndustryControlFlag::NoProductionIncrease) && new_prod > old_prod) continue;
2894
2895 /* Do not stop closing the industry when it has the lowest possible production rate */
2896 if (new_prod == old_prod && old_prod > 1) {
2897 closeit = false;
2898 continue;
2899 }
2900
2901 percent = (old_prod == 0) ? 100 : (new_prod * 100 / old_prod - 100);
2902 p.rate = new_prod;
2903
2904 /* Close the industry when it has the lowest possible production rate */
2905 if (new_prod > 1) closeit = false;
2906
2907 if (abs(percent) >= 10) {
2908 ReportNewsProductionChangeIndustry(i, p.cargo, percent);
2909 }
2910 }
2911 }
2912 }
2913
2914 /* If override flags are set, prevent actually changing production if any was decided on */
2915 if (i->ctlflags.Test(IndustryControlFlag::NoProductionDecrease) && (div > 0 || increment < 0)) return;
2916 if (i->ctlflags.Test(IndustryControlFlag::NoProductionIncrease) && (mul > 0 || increment > 0)) return;
2918 div = 0;
2919 mul = 0;
2920 increment = 0;
2921 }
2922
2923 if (!callback_enabled && indspec->life_type.Test(IndustryLifeType::Processing)) {
2924 if (TimerGameEconomy::year - i->last_prod_year >= PROCESSING_INDUSTRY_ABANDONMENT_YEARS && Chance16(1, original_economy ? 2 : 180)) {
2925 closeit = true;
2926 }
2927 }
2928
2929 /* Increase if needed */
2930 while (mul-- != 0 && i->prod_level < PRODLEVEL_MAXIMUM) {
2931 i->prod_level = std::min<int>(i->prod_level * 2, PRODLEVEL_MAXIMUM);
2932 recalculate_multipliers = true;
2933 if (str == STR_NULL) str = indspec->production_up_text;
2934 }
2935
2936 /* Decrease if needed */
2937 while (div-- != 0 && !closeit) {
2938 if (i->prod_level == PRODLEVEL_MINIMUM) {
2939 closeit = true;
2940 break;
2941 } else {
2942 i->prod_level = std::max<int>(i->prod_level / 2, PRODLEVEL_MINIMUM);
2943 recalculate_multipliers = true;
2944 if (str == STR_NULL) str = indspec->production_down_text;
2945 }
2946 }
2947
2948 /* Increase or Decreasing the production level if needed */
2949 if (increment != 0) {
2950 if (increment < 0 && i->prod_level == PRODLEVEL_MINIMUM) {
2951 closeit = true;
2952 } else {
2954 recalculate_multipliers = true;
2955 }
2956 }
2957
2958 /* Recalculate production_rate
2959 * For non-smooth economy these should always be synchronized with prod_level */
2960 if (recalculate_multipliers) i->RecomputeProductionMultipliers();
2961
2962 /* Close if needed and allowed */
2966 str = indspec->closure_text;
2967 }
2968
2969 if (!suppress_message && str != STR_NULL) {
2970 NewsType nt;
2971 /* Compute news category */
2972 if (closeit) {
2974 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index));
2975 Game::NewEvent(new ScriptEventIndustryClose(i->index));
2976 } else {
2977 switch (WhoCanServiceIndustry(i)) {
2978 case 0: nt = NewsType::IndustryNobody; break;
2979 case 1: nt = NewsType::IndustryOther; break;
2980 case 2: nt = NewsType::IndustryCompany; break;
2981 default: NOT_REACHED();
2982 }
2983 }
2984 /* Set parameters of news string */
2985 EncodedString headline;
2986 if (str > STR_LAST_STRINGID) {
2987 headline = GetEncodedString(str, STR_TOWN_NAME, i->town->index, indspec->name);
2988 } else if (closeit) {
2989 headline = GetEncodedString(str, STR_FORMAT_INDUSTRY_NAME, i->town->index, indspec->name);
2990 } else {
2991 headline = GetEncodedString(str, i->index);
2992 }
2993 /* and report the news to the user */
2994 if (closeit) {
2995 AddTileNewsItem(std::move(headline), nt, i->location.tile + TileDiffXY(1, 1));
2996 } else {
2997 AddIndustryNewsItem(std::move(headline), nt, i->index);
2998 }
2999 }
3000}
3001
3009static IntervalTimer<TimerGameEconomy> _economy_industries_daily({TimerGameEconomy::DAY, TimerGameEconomy::Priority::INDUSTRY}, [](auto)
3010{
3012
3013 /* Bits 16-31 of industry_construction_counter contain the number of industries to change/create today,
3014 * the lower 16 bit are a fractional part that might accumulate over several days until it
3015 * is sufficient for an industry. */
3016 uint16_t change_loop = _economy.industry_daily_change_counter >> 16;
3017
3018 /* Reset the active part of the counter, just keeping the "fractional part" */
3019 _economy.industry_daily_change_counter &= 0xFFFF;
3020
3021 if (change_loop == 0) {
3022 return; // Nothing to do? get out
3023 }
3024
3026
3027 /* perform the required industry changes for the day */
3028
3029 uint perc = 3; // Between 3% and 9% chance of creating a new industry.
3031 perc = std::min(9u, perc + (_industry_builder.wanted_inds >> 16) - GetCurrentTotalNumberOfIndustries());
3032 }
3033 for (uint16_t j = 0; j < change_loop; j++) {
3034 if (Chance16(perc, 100)) {
3036 } else {
3038 if (i != nullptr) {
3039 ChangeIndustryProduction(i, false);
3041 }
3042 }
3043 }
3044
3045 cur_company.Restore();
3046
3047 /* production-change */
3048 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, IDIWD_PRODUCTION_CHANGE);
3049});
3050
3051static IntervalTimer<TimerGameEconomy> _economy_industries_monthly({TimerGameEconomy::MONTH, TimerGameEconomy::Priority::INDUSTRY}, [](auto)
3052{
3054
3056
3057 for (Industry *i : Industry::Iterate()) {
3059 if (i->prod_level == PRODLEVEL_CLOSURE) {
3060 delete i;
3061 } else {
3062 ChangeIndustryProduction(i, true);
3064 }
3065 }
3066
3067 cur_company.Restore();
3068
3069 /* production-change */
3070 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, IDIWD_PRODUCTION_CHANGE);
3071});
3072
3073
3074void InitializeIndustries()
3075{
3076 Industry::industries.fill({});
3077 _industry_sound_tile = TileIndex{};
3078
3080}
3081
3084{
3085 int count = 0;
3086 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
3087 if (Industry::GetIndustryTypeCount(it) > 0) continue; // Types of existing industries can be skipped.
3088
3089 bool force_at_least_one;
3090 uint32_t chance = GetScaledIndustryGenerationProbability(it, &force_at_least_one);
3091 if (chance == 0 || !force_at_least_one) continue; // Types that are not available can be skipped.
3092
3093 const IndustrySpec *is = GetIndustrySpec(it);
3094 ShowErrorMessage(GetEncodedString(STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES, is->name),
3095 GetEncodedString(STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION), WL_WARNING);
3096
3097 count++;
3098 if (count >= 3) break; // Don't swamp the user with errors.
3099 }
3100}
3101
3110
3116{
3117 /* Lumber mills are neither raw nor processing */
3120}
3121
3127{
3128 /* Building raw industries like secondary uses different price base */
3129 return (_price[(_settings_game.construction.raw_industry_construction == 1 && this->IsRawIndustry()) ?
3130 PR_BUILD_INDUSTRY_RAW : PR_BUILD_INDUSTRY] * this->cost_multiplier) >> 8;
3131}
3132
3140{
3141 return (_price[PR_CLEAR_INDUSTRY] * this->removal_cost_multiplier) >> 8;
3142}
3143
3158
3159static CommandCost TerraformTile_Industry(TileIndex tile, DoCommandFlags flags, int z_new, Slope tileh_new)
3160{
3161 if (AutoslopeEnabled()) {
3162 /* We imitate here TTDP's behaviour:
3163 * - Both new and old slope must not be steep.
3164 * - TileMaxZ must not be changed.
3165 * - Allow autoslope by default.
3166 * - Disallow autoslope if callback succeeds and returns non-zero.
3167 */
3168 Slope tileh_old = GetTileSlope(tile);
3169 /* TileMaxZ must not be changed. Slopes must not be steep. */
3170 if (!IsSteepSlope(tileh_old) && !IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) {
3171 const IndustryGfx gfx = GetIndustryGfx(tile);
3172 const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
3173
3174 /* Call callback 3C 'disable autosloping for industry tiles'. */
3176 /* If the callback fails, allow autoslope. */
3177 uint16_t res = GetIndustryTileCallback(CBID_INDTILE_AUTOSLOPE, 0, 0, gfx, Industry::GetByTile(tile), tile);
3178 if (res == CALLBACK_FAILED || !ConvertBooleanCallback(itspec->grf_prop.grffile, CBID_INDTILE_AUTOSLOPE, res)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
3179 } else {
3180 /* allow autoslope */
3181 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
3182 }
3183 }
3184 }
3185 return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
3186}
3187
3188extern const TileTypeProcs _tile_type_industry_procs = {
3189 DrawTile_Industry, // draw_tile_proc
3190 GetSlopePixelZ_Industry, // get_slope_z_proc
3191 ClearTile_Industry, // clear_tile_proc
3192 AddAcceptedCargo_Industry, // add_accepted_cargo_proc
3193 GetTileDesc_Industry, // get_tile_desc_proc
3194 GetTileTrackStatus_Industry, // get_tile_track_status_proc
3195 ClickTile_Industry, // click_tile_proc
3196 AnimateTile_Industry, // animate_tile_proc
3197 TileLoop_Industry, // tile_loop_proc
3198 ChangeTileOwner_Industry, // change_tile_owner_proc
3199 nullptr, // add_produced_cargo_proc
3200 nullptr, // vehicle_enter_tile_proc
3201 GetFoundation_Industry, // get_foundation_proc
3202 TerraformTile_Industry, // terraform_tile_proc
3203};
3204
3205bool IndustryCompare::operator() (const IndustryListEntry &lhs, const IndustryListEntry &rhs) const
3206{
3207 /* Compare by distance first and use index as a tiebreaker. */
3208 return std::tie(lhs.distance, lhs.industry->index) < std::tie(rhs.distance, rhs.industry->index);
3209}
3210
3216{
3217 auto ita = std::find_if(std::rbegin(ind->accepted), std::rend(ind->accepted), [](const auto &a) { return IsValidCargoType(a.cargo); });
3218 ind->accepted.erase(ita.base(), std::end(ind->accepted));
3219 ind->accepted.shrink_to_fit();
3220
3221 auto itp = std::find_if(std::rbegin(ind->produced), std::rend(ind->produced), [](const auto &p) { return IsValidCargoType(p.cargo); });
3222 ind->produced.erase(itp.base(), std::end(ind->produced));
3223 ind->produced.shrink_to_fit();
3224}
Base functions for all AIs.
void AddAnimatedTile(TileIndex tile, bool mark_dirty)
Add the given tile to the animated tile table (if it does not exist yet).
void DeleteAnimatedTile(TileIndex tile, bool immediate)
Stops animation on the given tile.
Tile animation!
Functions related to autoslope.
bool AutoslopeEnabled()
Tests if autoslope is enabled for _current_company.
Definition autoslope.h:65
Class for backupping variables and making sure they are restored later.
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
bool IsBridgeAbove(Tile t)
checks if a bridge is set above the ground of this tile
Definition bridge_map.h:45
Tables with default industry layouts and behaviours.
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:23
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:106
static constexpr CargoLabel CT_PASSENGERS
Available types of cargo Labels may be re-used between different climates.
Definition cargo_type.h:31
Cheats _cheats
All the cheats.
Definition cheat.cpp:16
Types related to cheating.
static void BroadcastNewEvent(ScriptEvent *event, CompanyID skip_company=CompanyID::Invalid())
Broadcast a new event to all active AIs.
Definition ai_core.cpp:255
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr bool IsValid() const
Test that the raw value of this bit set is valid.
constexpr Timpl & Set()
Set all bits.
constexpr bool Any(const Timpl &other) const
Test if any of the given values are set.
constexpr Timpl & Reset(Tvalue_type value)
Reset the value-th bit.
Common return value for all commands.
bool Succeeded() const
Did this command succeed?
bool Failed() const
Did this command fail?
Container for an encoded string, created by GetEncodedString.
Enum-as-bit-set wrapper.
static void NewEvent(class ScriptEvent *event)
Queue a new event for a Game Script.
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
void ResetOverride()
Resets the override, which is used while initializing game.
static constexpr TimerGameTick::Ticks INDUSTRY_CUT_TREE_TICKS
Cycle duration for lumber mill's extra action.
static constexpr TimerGameTick::Ticks INDUSTRY_PRODUCE_TICKS
Cycle duration for industry production.
Wrapper class to abstract away the way the tiles are stored.
Definition map_func.h:25
static Date date
Current date in days (day counter).
static Year year
Current year, starting at 0.
static Year year
Current year, starting at 0.
static TickCounter counter
Monotonic counter, in ticks, since start of game.
Map accessors for 'clear' tiles.
bool IsClearGround(Tile t, ClearGround ct)
Set the type of clear tile.
Definition clear_map.h:59
void SetFence(Tile t, DiagDirection side, uint h)
Sets the type of fence (and whether there is one) for the given border.
Definition clear_map.h:228
IndustryID GetIndustryIndexOfField(Tile t)
Get the industry (farm) that made the field.
Definition clear_map.h:183
@ CLEAR_FIELDS
3
Definition clear_map.h:23
@ CLEAR_DESERT
1,3
Definition clear_map.h:25
void SetIndustryIndexOfField(Tile t, IndustryID i)
Set the industry (farm) that made the field.
Definition clear_map.h:195
void MakeField(Tile t, uint field_type, IndustryID industry)
Make a (farm) field tile.
Definition clear_map.h:268
void SetClearCounter(Tile t, uint c)
Sets the counter used to advance to the next clear density/field type.
Definition clear_map.h:132
uint GetFence(Tile t, DiagDirection side)
Is there a fence at the given border?
Definition clear_map.h:209
bool IsSnowTile(Tile t)
Test if a tile is covered with snow.
Definition clear_map.h:35
CommandCost CommandCostWithParam(StringID str, uint64_t value)
Return an error status, with string and parameter.
Definition command.cpp:417
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ Execute
execute the given command
@ NoModifyTownRating
do not change town rating
@ NoTestTownRating
town rating does not disallow you from building
@ NoWater
don't allow building on water
@ Auto
don't allow building on structures
Definition of stuff that is very close to a company, like the company struct itself.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
CompanyID _current_company
Company currently doing an action.
bool IsLocalCompany()
Is the current company the local company?
static constexpr Owner OWNER_DEITY
The object is owned by a superuser / goal script.
static constexpr Owner OWNER_TOWN
A town owns the tile, or a town is expanding.
static constexpr Owner OWNER_NONE
The tile has no ownership.
static constexpr Owner INVALID_OWNER
An invalid owner.
static constexpr Owner OWNER_WATER
The tile/execution is done by "water".
DiagDirection ReverseDiagDir(DiagDirection d)
Returns the reverse direction of the given DiagDirection.
Axis OtherAxis(Axis a)
Select the other axis as provided.
Axis DiagDirToAxis(DiagDirection d)
Convert a DiagDirection to the axis.
DiagDirection
Enumeration for diagonal directions.
@ DIAGDIR_NE
Northeast, upper right on your monitor.
@ DIAGDIR_NW
Northwest.
@ DIAGDIR_SE
Southeast.
@ DIAGDIR_SW
Southwest.
static uint ScaleByInverseCargoScale(uint num, bool town)
Scale a number by the inverse of the cargo scale setting, e.g.
bool EconomyIsInRecession()
Is the economy in recession?
uint ScaleByCargoScale(uint num, bool town)
Scale a number by the cargo scale setting.
@ EXPENSES_CONSTRUCTION
Construction costs.
@ EXPENSES_OTHER
Other expenses.
EffectVehicle * CreateEffectVehicle(int x, int y, int z, EffectVehicleType type)
Create an effect vehicle at a particular location.
EffectVehicle * CreateEffectVehicleAbove(int x, int y, int z, EffectVehicleType type)
Create an effect vehicle above a particular location.
Base class for all effect vehicles.
Functions related to effect vehicles.
@ EV_BUBBLE
Bubble of bubble generator (industry).
@ EV_CHIMNEY_SMOKE
Smoke of power plant (industry).
@ EV_COPPER_MINE_SMOKE
Smoke at copper mine.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
Functions related to errors.
@ WL_WARNING
Other information.
Definition error.h:25
@ WL_INFO
Used for DoCommand-like (and some non-fatal AI GUI) errors/information.
Definition error.h:24
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, CommandCost &cc)
Display an error message in a window.
Base functions for all Games.
bool _generating_world
Whether we are generating the map or not.
Definition genworld.cpp:74
Functions related to world/map generation.
void IncreaseGeneratingWorldProgress(GenWorldProgress cls)
Increases the current stage of the world generation with one.
@ LG_TERRAGENESIS
TerraGenesis Perlin landscape generator.
Definition genworld.h:22
@ GWP_INDUSTRY
Generate industries.
Definition genworld.h:67
void SetGeneratingWorldProgress(GenWorldProgress cls, uint total)
Set the total of a stage of the world generation.
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
uint8_t GetSnowLine()
Get the current snow line, either variable or static.
uint8_t HighestSnowLine()
Get the highest possible snow line height, either variable or static.
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
Mark a tile given by its index dirty for repaint.
Base of all industries.
static constexpr uint8_t PRODLEVEL_MAXIMUM
the industry is running at full speed
Definition industry.h:36
void ReleaseDisastersTargetingIndustry(IndustryID)
Marks all disasters targeting this industry in such a way they won't call Industry::Get(v->dest_tile)...
static constexpr uint8_t PRODLEVEL_DEFAULT
default level set when the industry is created
Definition industry.h:35
static const TimerGameEconomy::Year PROCESSING_INDUSTRY_ABANDONMENT_YEARS
If a processing industry doesn't produce for this many consecutive economy years, it may close.
Definition industry.h:26
static constexpr uint8_t PRODLEVEL_MINIMUM
below this level, the industry is set to be closing
Definition industry.h:34
static constexpr uint8_t PRODLEVEL_CLOSURE
signal set to actually close the industry
Definition industry.h:33
@ ExternalProdLevel
Indicates that the production level of the industry is externally controlled.
@ NoClosure
Industry can not close regardless of production level or time since last delivery.
@ NoProductionDecrease
When industry production change is evaluated, rolls to decrease are ignored.
@ NoProductionIncrease
When industry production change is evaluated, rolls to increase are ignored.
static uint16_t GetIndustryGamePlayProbability(IndustryType it, uint8_t *min_number)
Compute the probability for constructing a new industry during game play.
static CommandCost CheckNewIndustry_Water(TileIndex tile)
Check the conditions of CHECK_WATER (Industry should be in the desert).
static uint32_t GetScaledIndustryGenerationProbability(IndustryType it, bool *force_at_least_one)
Compute the appearance probability for an industry during map creation.
static CheckNewIndustryProc *const _check_new_industry_procs[CHECK_END]
Check functions for different types of industry.
static CommandCost CheckIfIndustryIsAllowed(TileIndex tile, IndustryType type, const Town *t)
Is the industry allowed to be built at this place for the town?
const IndustrySpec * GetIndustrySpec(IndustryType thistype)
Accessor for array _industry_specs.
static bool TransportIndustryGoods(TileIndex tile)
Move produced cargo from industry to nearby stations.
CommandCost CmdIndustrySetExclusivity(DoCommandFlags flags, IndustryID ind_id, Owner company_id, bool consumer)
Change exclusive consumer or supplier for the industry.
static CommandCost CheckIfIndustryTileSlopes(TileIndex tile, const IndustryTileLayout &layout, size_t layout_index, IndustryType type, uint16_t initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type, bool *custom_shape_check=nullptr)
Check slope requirements for industry tiles.
static uint GetCurrentTotalNumberOfIndustries()
Get total number of industries existing in the game.
static CommandCost CheckNewIndustry_OilRefinery(TileIndex tile)
Check the conditions of CHECK_REFINERY (Industry should be positioned near edge of the map).
static CommandCost CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTileLayout &layout, IndustryType type)
Are the tiles of the industry free?
CommandCost CmdIndustrySetProduction(DoCommandFlags flags, IndustryID ind_id, uint8_t prod_level, bool show_news, const EncodedString &custom_news)
Set industry production.
static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, DoCommandFlags flags, const IndustryTileLayout &layout)
This function tries to flatten out the land below an industry, without damaging the surroundings too ...
static void PlaceInitialIndustry(IndustryType type, bool try_hard)
Try to build a industry on the map.
static CommandCost CheckNewIndustry_BubbleGen(TileIndex tile)
Check the conditions of CHECK_BUBBLEGEN (Industry should be in low land).
static CommandCost CheckNewIndustry_Farm(TileIndex tile)
Check the conditions of CHECK_FARM (Industry should be below snow-line in arctic).
static void AdvertiseIndustryOpening(const Industry *ind)
Advertise about a new industry opening.
static void ChopLumberMillTrees(Industry *i)
Perform a circular search around the Lumber Mill in order to find trees to cut.
static bool CheckScaledDistanceFromEdge(TileIndex tile, uint maxdist)
Check if a tile is within a distance from map edges, scaled by map dimensions independently.
static bool SearchLumberMillTrees(TileIndex tile, void *)
Search callback function for ChopLumberMillTrees.
static void ReportNewsProductionChangeIndustry(Industry *ind, CargoType cargo, int percent)
Report news that industry production has changed significantly.
bool IsTileForestIndustry(TileIndex tile)
Check whether the tile is a forest.
const IndustryTileSpec * GetIndustryTileSpec(IndustryGfx gfx)
Accessor for array _industry_tile_specs.
static void CanCargoServiceIndustry(CargoType cargo, Industry *ind, bool *c_accepts, bool *c_produces)
Can given cargo type be accepted or produced by the industry?
void GenerateIndustries()
This function will create random industries during game creation.
static void ProduceIndustryGoodsHelper(Industry *i, bool scale)
Helper for ProduceIndustryGoods that scales and produces cargos.
IndustryBuildData _industry_builder
In-game manager of industries.
static Industry * PlaceIndustry(IndustryType type, IndustryAvailabilityCallType creation_type, bool try_hard)
Try to place the industry in the game.
static CommandCost CheckNewIndustry_Plantation(TileIndex tile)
Check the conditions of CHECK_PLANTATION (Industry should NOT be in the desert).
void CheckIndustries()
Verify whether the generated industries are complete, and warn the user if not.
static void PopulateStationsNearby(Industry *ind)
Populate an industry's list of nearby stations, and if it accepts any cargo, also add the industry to...
static CommandCost CheckNewIndustry_Forest(TileIndex tile)
Check the conditions of CHECK_FOREST (Industry should be build above snow-line in arctic climate).
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)
Put an industry on the map.
CommandCost CheckNewIndustryProc(TileIndex tile)
Industrytype check function signature.
static CommandCost CreateNewIndustryHelper(TileIndex tile, IndustryType type, DoCommandFlags flags, const IndustrySpec *indspec, size_t layout_index, uint32_t random_var8f, uint16_t random_initial_bits, Owner founder, IndustryAvailabilityCallType creation_type, Industry **ip)
Helper function for Build/Fund an industry.
static int WhoCanServiceIndustry(Industry *ind)
Compute who can service the industry.
void ResetIndustries()
This function initialize the spec arrays of both industry and industry tiles.
static CommandCost CheckIfFarEnoughFromConflictingIndustry(TileIndex tile, IndustryType type)
Check that the new industry is far enough from conflicting industries.
static bool IsSuitableForFarmField(TileIndex tile, bool allow_fields)
Check whether the tile can be replaced by a farm field.
static CommandCost CheckNewIndustry_OilRig(TileIndex tile)
Check the conditions of CHECK_OIL_RIG (Industries at sea should be positioned near edge of the map).
void TrimIndustryAcceptedProduced(Industry *ind)
Remove unused industry accepted/produced slots – entries after the last slot with valid cargo.
static uint GetNumberOfIndustries()
Get wanted number of industries on the map.
CommandCost CmdBuildIndustry(DoCommandFlags flags, TileIndex tile, IndustryType it, uint32_t first_layout, bool fund, uint32_t seed)
Build/Fund an industry.
static bool CheckIndustryCloseDownProtection(IndustryType type)
Protects an industry from closure if the appropriate flags and conditions are met CanCloseLastInstanc...
static void SetupFarmFieldFence(TileIndex tile, int size, uint8_t type, DiagDirection side)
Build farm field fence.
CommandCost CmdIndustrySetFlags(DoCommandFlags flags, IndustryID ind_id, IndustryControlFlags ctlflags)
Set industry control flags.
static IntervalTimer< TimerGameEconomy > _economy_industries_daily({TimerGameEconomy::DAY, TimerGameEconomy::Priority::INDUSTRY}, [](auto) { _economy.industry_daily_change_counter+=_economy.industry_daily_increment;uint16_t change_loop=_economy.industry_daily_change_counter > > 16;_economy.industry_daily_change_counter &=0xFFFF;if(change_loop==0) { return;} Backup< CompanyID > cur_company(_current_company, OWNER_NONE);uint perc=3;if((_industry_builder.wanted_inds > > 16) > GetCurrentTotalNumberOfIndustries()) { perc=std::min(9u, perc+(_industry_builder.wanted_inds > > 16) - GetCurrentTotalNumberOfIndustries());} for(uint16_t j=0;j< change_loop;j++) { if(Chance16(perc, 100)) { _industry_builder.TryBuildNewIndustry();} else { Industry *i=Industry::GetRandom();if(i !=nullptr) { ChangeIndustryProduction(i, false);SetWindowDirty(WC_INDUSTRY_VIEW, i->index);} } } cur_company.Restore();InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, IDIWD_PRODUCTION_CHANGE);})
Every economy day handler for the industry changes Taking the original map size of 256*256,...
IndustryType GetIndustryType(Tile tile)
Retrieve the type for this industry.
static void UpdateIndustryStatistics(Industry *i)
Monthly update of industry statistics.
static CommandCost FindTownForIndustry(TileIndex tile, IndustryType type, Town **t)
Find a town for the industry, while checking for multiple industries in the same town.
static CommandCost CheckNewIndustry_NULL(TileIndex)
Check the conditions of CHECK_NOTHING (Always succeeds).
static Industry * CreateNewIndustry(TileIndex tile, IndustryType type, IndustryAvailabilityCallType creation_type)
Create a new industry of random layout.
static void ChangeIndustryProduction(Industry *i, bool monthly)
Change industry production or do closure.
static CommandCost CheckNewIndustry_Lumbermill(TileIndex tile)
Check the conditions of CHECK_LUMBERMILL (Industry should be in the rainforest).
CommandCost CmdIndustrySetText(DoCommandFlags flags, IndustryID ind_id, const EncodedString &text)
Change additional industry text.
Command definitions related to industries.
Information about the behaviour of the default industry tiles.
static const DrawIndustryCoordinates _coal_plant_sparks[]
Movement of the sparks , only used for Power Station.
static const DrawBuildingsTileStruct _industry_draw_tile_data[NEW_INDUSTRYTILEOFFSET *4]
Structure for industry tiles drawing.
void SetIndustryCompleted(Tile tile)
Set if the industry that owns the tile as under construction or not.
void SetIndustryGfx(Tile t, IndustryGfx gfx)
Set the industry graphics ID for the given industry tile.
void ResetIndustryConstructionStage(Tile tile)
Reset the construction stage counter of the industry, as well as the completion bit.
void SetIndustryConstructionCounter(Tile tile, uint8_t value)
Sets this industry tile's construction counter value.
IndustryGfx GetIndustryGfx(Tile t)
Get the industry graphics ID for the given industry tile.
bool IsIndustryCompleted(Tile t)
Is this industry tile fully built?
IndustryID GetIndustryIndex(Tile t)
Get the industry ID of the given tile.
uint8_t GetIndustryConstructionCounter(Tile tile)
Returns this industry tile's construction counter value.
void MakeIndustry(Tile t, IndustryID index, IndustryGfx gfx, uint8_t random, WaterClass wc)
Make the given tile an industry tile.
void SetIndustryAnimationLoop(Tile tile, uint8_t count)
Set the animation loop number.
@ GFX_WATERTILE_SPECIALCHECK
not really a tile, but rather a very special check
void SetIndustryConstructionStage(Tile tile, uint8_t value)
Sets the industry construction stage of the specified tile.
uint8_t GetIndustryAnimationLoop(Tile tile)
Get the animation loop number.
uint8_t GetIndustryConstructionStage(Tile tile)
Returns the industry construction stage of the specified tile.
static const IndustryGfx NEW_INDUSTRYTILEOFFSET
original number of tiles
static const IndustryGfx INDUSTRYTILE_NOANIM
flag to mark industry tiles as having no animation
static const int INDUSTRY_ORIGINAL_NUM_INPUTS
Original number of accepted cargo types.
static const int INDUSTRY_NUM_OUTPUTS
Number of cargo types an industry can produce.
static const int INDUSTRY_NUM_INPUTS
Number of cargo types an industry can accept.
static const IndustryType NUM_INDUSTRYTYPES
total number of industry types, new and old; limited to 240 because we need some special ids like IT_...
static const IndustryGfx INVALID_INDUSTRYTILE
one above amount is considered invalid
static const IndustryGfx NUM_INDUSTRYTILES
total number of industry tiles, new and old
static const int INDUSTRY_COMPLETED
final stage of industry construction.
@ NoBuildMapCreation
Do not force one instance of this type to appear on map generation.
@ CutTrees
cuts trees and produce first output cargo from them (lumber mill)
@ PlantOnBuild
Fields are planted around when built (all farms)
@ Before1950
can only be built before 1950 (oil wells)
@ BuiltOnWater
is built on water (oil rig)
@ DontIncrProd
do not increase production (oil wells) in the temperate climate
@ CargoTypesUnlimited
Allow produced/accepted cargoes callbacks to supply more than 2 and 3 types.
@ After1960
can only be built after 1960 (oil rigs)
@ PlantFields
periodically plants fields around itself (temp and arctic farms)
@ Town1200More
can only be built in towns larger than 1200 inhabitants (temperate bank)
@ NoPaxProdClamp
Do not clamp production of passengers. (smooth economy only)
@ CanCloseLastInstance
Allow closing down the last instance of this type.
@ OnlyNearTown
is always built near towns (toy shop)
@ AcceptsAllCargo
Tile always accepts all cargoes the associated industry accepts.
@ Processing
Like factories.
@ Organic
Like forests.
@ Extractive
Like mines.
IndustryGfx GetTranslatedIndustryTileID(IndustryGfx gfx)
Do industry gfx ID translation for NewGRFs.
std::vector< IndustryTileLayoutTile > IndustryTileLayout
A complete tile layout for an industry is a list of tiles.
@ CHECK_REFINERY
Industry should be positioned near edge of the map.
@ CHECK_END
End marker of the industry check procedures.
@ CHECK_OIL_RIG
Industries at sea should be positioned near edge of the map.
@ ICT_MAP_GENERATION
during random map creation
@ ICT_NORMAL_GAMEPLAY
either by user or random creation process
@ ICT_SCENARIO_EDITOR
while editing a scenario
static constexpr IndustryLifeTypes INDUSTRYLIFE_BLACK_HOLE
Like power plants and banks.
void DrawFoundation(TileInfo *ti, Foundation f)
Draw foundation f at tile ti.
Functions related to OTTD's landscape.
Command definitions related to landscape (slopes etc.).
@ Random
Randomise borders.
bool CircularTileSearch(TileIndex *tile, uint size, TestTileOnSearchProc proc, void *user_data)
Function performing a search around a center tile and going outward, thus in circle.
Definition map.cpp:243
uint DistanceMax(TileIndex t0, TileIndex t1)
Gets the biggest distance component (x or y) between the two given tiles.
Definition map.cpp:174
uint DistanceFromEdgeDir(TileIndex tile, DiagDirection dir)
Gets the distance to the edge of the map in given direction.
Definition map.cpp:219
TileIndex TileAddWrap(TileIndex tile, int addx, int addy)
This function checks if we add addx/addy to tile, if we do wrap around the edges.
Definition map.cpp:93
TileIndex TileAddXY(TileIndex tile, int x, int y)
Adds a given offset to a tile.
Definition map_func.h:469
TileIndexDiff ToTileIndexDiff(TileIndexDiffC tidc)
Return the offset between two tiles from a TileIndexDiffC struct.
Definition map_func.h:439
TileIndexDiff TileDiffXY(int x, int y)
Calculates an offset for the given coordinate(-offset).
Definition map_func.h:388
TileIndexDiff TileOffsByAxis(Axis axis)
Convert an Axis to a TileIndexDiff.
Definition map_func.h:554
#define RandomTile()
Get a valid random tile.
Definition map_func.h:663
static debug_inline uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:424
static debug_inline uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:414
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition map_func.h:569
int32_t TileIndexDiff
An offset value between two tiles.
Definition map_type.h:23
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition math_func.hpp:23
constexpr uint CeilDiv(uint a, uint b)
Computes ceil(a / b) for non-negative a and b.
constexpr T Delta(const T a, const T b)
Returns the (absolute) difference between two (scalar) variables.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
constexpr uint ClampU(const uint a, const uint min, const uint max)
Clamp an unsigned integer between an interval.
StringID MapGRFStringID(uint32_t grfid, GRFStringID str)
Used when setting an object's property to map to the GRF's strings while taking in consideration the ...
@ IAT_TILELOOP
Trigger in the periodic tile loop.
@ IAT_CONSTRUCTION_STATE_CHANGE
Trigger whenever the construction state changes.
@ IAT_INDUSTRY_DISTRIBUTES_CARGO
Trigger when cargo is distributed.
@ IAT_INDUSTRY_TICK
Trigger every tick.
static const uint8_t ANIM_STATUS_NO_ANIMATION
There is no animation.
@ InputCargoTypes
customize the cargoes the industry requires
@ ProductionChange
controls random production change
@ DecideColour
give a custom colour to newly build industries
@ SpecialEffect
control special effects
@ ProdChangeBuild
initialise production level on construction
@ Production256Ticks
call production callback every 256 ticks
@ Location
check industry construction on given area
@ MonthlyProdChange
controls monthly random production change
@ ProductionCargoArrival
call production callback when cargo arrives at the industry
@ OutputCargoTypes
customize the cargoes the industry produces
@ CBID_INDUSTRY_OUTPUT_CARGO_TYPES
Customize the output cargo types of a newly build industry.
@ CBID_INDUSTRY_SPECIAL_EFFECT
Called to determine industry special effects.
@ CBID_INDTILE_AUTOSLOPE
Called to determine if industry can alter the ground below industry tile.
@ CBID_INDUSTRY_DECIDE_COLOUR
Called to determine the colour of an industry.
@ CBID_INDTILE_DRAW_FOUNDATIONS
Called to determine the type (if any) of foundation to draw for industry tile.
@ CBID_INDUSTRY_PRODUCTION_CHANGE
Called on production changes, so it can be adjusted.
@ CBID_INDUSTRY_MONTHLYPROD_CHANGE
Called monthly on production changes, so it can be adjusted more frequently.
@ CBID_INDUSTRY_PROD_CHANGE_BUILD
Called when industry is built to set initial production level.
@ CBID_INDTILE_CARGO_ACCEPTANCE
Called to query the cargo acceptance of the industry tile.
@ CBID_INDTILE_ACCEPT_CARGO
Called to determine which cargoes an industry should accept.
@ CBID_INDUSTRY_INPUT_CARGO_TYPES
Customize the input cargo types of a newly build industry.
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
@ ShapeCheck
decides slope suitability
@ AcceptCargo
decides accepted types
@ CargoAcceptance
decides amount of cargo acceptance
@ DrawFoundations
decides if default foundations need to be drawn
@ Autoslope
decides allowance of autosloping
CargoType GetCargoTranslation(uint8_t cargo, const GRFFile *grffile, bool usebit)
Translate a GRF-local cargo slot/bitnum into a CargoType.
Cargo support for NewGRFs.
void ErrorUnknownCallbackResult(uint32_t grfid, uint16_t cbid, uint16_t cb_res)
Record that a NewGRF returned an unknown/invalid callback result.
bool ConvertBooleanCallback(const GRFFile *grffile, uint16_t cbid, uint16_t cb_res)
Converts a callback result into a boolean.
GRFConfig * GetGRFConfig(uint32_t grfid, uint32_t mask)
Retrieve a NewGRF from the current config by its grfid.
Functions/types related to NewGRF debugging.
void DeleteNewGRFInspectWindow(GrfSpecFeature feature, uint index)
Delete inspect window for a given feature and index.
CommandCost CheckIfCallBackAllowsCreation(TileIndex tile, IndustryType type, size_t layout, uint32_t seed, uint16_t initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type)
Check that the industry callback allows creation of the industry.
void IndustryProductionCallback(Industry *ind, int reason)
Get the industry production callback and apply it to the industry.
uint32_t GetIndustryProbabilityCallback(IndustryType type, IndustryAvailabilityCallType creation_type, uint32_t default_prob)
Check with callback CBID_INDUSTRY_PROBABILITY whether the industry can be built.
uint16_t GetIndustryCallback(CallbackID callback, uint32_t param1, uint32_t param2, Industry *industry, IndustryType type, TileIndex tile)
Perform an industry callback.
bool IndustryTemporarilyRefusesCargo(Industry *ind, CargoType cargo_type)
Check whether an industry temporarily refuses to accept a certain cargo.
IndustryAvailabilityCallType
From where has callback CBID_INDUSTRY_PROBABILITY been called.
@ IACT_USERCREATION
from the Fund/build window
@ IACT_RANDOMCREATION
during creation of random ingame industry
@ IACT_MAPGENERATION
during random map generation
@ IACT_PROSPECTCREATION
from the Fund/build using prospecting
void TriggerIndustry(Industry *ind, IndustryTileTrigger trigger)
Trigger a random trigger for all industry tiles.
CommandCost PerformIndustryTileSlopeCheck(TileIndex ind_base_tile, TileIndex ind_tile, const IndustryTileSpec *its, IndustryType type, IndustryGfx gfx, size_t layout_index, uint16_t initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type)
Check the slope of a tile of a new industry.
void TriggerIndustryTile(TileIndex tile, IndustryTileTrigger trigger)
Trigger a random trigger for a single industry tile.
NewGRF handling of industry tiles.
@ INDTILE_TRIGGER_TILE_LOOP
The tile of the industry has been triggered during the tileloop.
@ INDUSTRY_TRIGGER_INDUSTRY_TICK
The industry has been triggered via its tick.
uint32_t GetRegister(uint i)
Gets the value of a so-called newgrf "register".
Functions related to news.
void DeleteIndustryNews(IndustryID iid)
Remove news regarding given industry.
NewsType
Type of news.
Definition news_type.h:28
@ IndustryCompany
Production changes of industry serviced by local company.
@ IndustryClose
Closing of industries.
@ IndustryOpen
Opening of industries.
@ IndustryNobody
Other industry production changes.
@ IndustryOther
Production changes of industry serviced by competitor(s)
Base for all objects.
@ OUFB_TRANSFER
Transfer all cargo onto the platform.
Definition order_type.h:71
@ OUFB_UNLOAD
Force unloading all cargo onto the platform, possibly not getting paid.
Definition order_type.h:70
Some methods of Pool are placed here in order to reduce compilation time and binary size.
#define INSTANTIATE_POOL_METHODS(name)
Force instantiation of pool methods so we don't get linker errors.
uint32_t RandomRange(uint32_t limit, const std::source_location location=std::source_location::current())
Pick a random number between 0 and limit - 1, inclusive.
bool Chance16I(const uint32_t a, const uint32_t b, const uint32_t r)
Checks if a given randomize-number is below a given probability.
bool Chance16(const uint32_t a, const uint32_t b, const std::source_location location=std::source_location::current())
Flips a coin with given probability.
bool Chance16R(const uint32_t a, const uint32_t b, uint32_t &r, const std::source_location location=std::source_location::current())
Flips a coin with a given probability and saves the randomize-number in a variable.
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:59
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:58
@ ID_CUSTOM
Custom number of industries.
@ ID_VERY_LOW
Very few industries at game start.
@ ID_END
Number of industry density settings.
@ ID_FUND_ONLY
The game does not build industries.
static constexpr int GetSlopeMaxZ(Slope s)
Returns the height of the highest corner of a slope relative to TileZ (= minimal height)
Definition slope_func.h:160
static constexpr bool IsSteepSlope(Slope s)
Checks if a slope is steep.
Definition slope_func.h:36
Foundation FlatteningFoundation(Slope s)
Returns the foundation needed to flatten a slope.
Definition slope_func.h:369
Slope ComplementSlope(Slope s)
Return the complement of a slope.
Definition slope_func.h:76
Slope
Enumeration for the slope-type.
Definition slope_type.h:48
@ SLOPE_W
the west corner of the tile is raised
Definition slope_type.h:50
@ SLOPE_E
the east corner of the tile is raised
Definition slope_type.h:52
@ SLOPE_S
the south corner of the tile is raised
Definition slope_type.h:51
@ SLOPE_N
the north corner of the tile is raised
Definition slope_type.h:53
@ SLOPE_SW
south and west corner are raised
Definition slope_type.h:56
@ SLOPE_FLAT
a flat tile
Definition slope_type.h:49
@ SLOPE_NE
north and east corner are raised
Definition slope_type.h:58
@ SLOPE_SE
south and east corner are raised
Definition slope_type.h:57
@ SLOPE_NW
north and west corner are raised
Definition slope_type.h:55
Foundation
Enumeration for Foundations.
Definition slope_type.h:93
@ FOUNDATION_LEVELED
The tile is leveled up to a flat slope.
Definition slope_type.h:95
@ FOUNDATION_NONE
The tile has no foundation, the slope remains unchanged.
Definition slope_type.h:94
Functions related to sound.
SoundFx
Sound effects from baseset.
Definition sound_type.h:45
@ SND_30_TOFFEE_QUARRY
48 == 0x30 Industry animation: toffee quarry: drill
Definition sound_type.h:95
@ SND_2E_BUBBLE_GENERATOR
46 == 0x2E Industry animation: bubble generator (1): generate bubble
Definition sound_type.h:93
@ SND_2D_SUGAR_MINE_1
45 == 0x2D Industry animation: sugar mine (1): shaking sieve
Definition sound_type.h:92
@ SND_2B_TOY_FACTORY_2
43 == 0x2B Industry animation: toy factory (2): stamp product
Definition sound_type.h:90
@ SND_38_LUMBER_MILL_1
56 == 0x38 Industry animation: lumber mill (1): chainsaw
Definition sound_type.h:103
@ SND_29_SUGAR_MINE_2
41 == 0x29 Industry animation: sugar mine (2): shaking sieve
Definition sound_type.h:88
@ SND_2C_TOY_FACTORY_1
44 == 0x2C Industry animation: toy factory (1): conveyor belt
Definition sound_type.h:91
@ SND_37_LUMBER_MILL_2
55 == 0x37 Industry animation: lumber mill (2): falling tree
Definition sound_type.h:102
@ SND_0C_POWER_STATION
10 == 0x0A Industry animation: power station: spark
Definition sound_type.h:57
@ SND_0B_MINE
9 == 0x09 Industry animation: coal/copper/gold mine: headgear
Definition sound_type.h:56
@ SND_36_LUMBER_MILL_3
54 == 0x36 Industry animation: lumber mill (3): crashing tree
Definition sound_type.h:101
@ SND_2A_TOY_FACTORY_3
42 == 0x2A Industry animation: toy factory (3): eject product
Definition sound_type.h:89
@ Industry
Source/destination is an industry.
PaletteID SpriteLayoutPaletteTransform(SpriteID image, PaletteID pal, PaletteID default_pal)
Applies PALETTE_MODIFIER_TRANSPARENT and PALETTE_MODIFIER_COLOUR to a palette entry of a sprite layou...
Definition sprite.h:155
PaletteID GroundSpritePaletteTransform(SpriteID image, PaletteID pal, PaletteID default_pal)
Applies PALETTE_MODIFIER_COLOUR to a palette entry of a ground sprite.
Definition sprite.h:174
Base classes/functions for stations.
void ForAllStationsAroundTiles(const TileArea &ta, Func func)
Call a function on all stations that have any part of the requested area within their catchment.
void ClearDockingTilesCheckingNeighbours(TileIndex tile)
Clear docking tile status from tiles around a removed dock, if the tile has no neighbours which would...
bool IsOilRig(Tile t)
Is tile t part of an oilrig?
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:271
Functions related to low-level strings.
void GetStringWithArgs(StringBuilder &builder, StringID string, StringParameters &args, uint case_index, bool game_script)
Get a parsed string with most special stringcodes replaced by the string parameters.
Definition strings.cpp:336
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:91
Functions related to OTTD's strings.
auto MakeParameters(Args &&... args)
Helper to create the StringParameters with its own buffer with the given parameter values.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
uint8_t status
Status; 0: no looping, 1: looping, 0xFF: no animation.
Class to backup a specific variable and restore it later.
const T & GetOriginalValue() const
Returns the backupped value.
void Restore()
Restore the variable.
VehicleType type
Type of vehicle.
Class for storing amounts of cargo.
Definition cargo_type.h:113
static void InvalidateAllFrom(Source src)
Invalidates (sets source_id to INVALID_SOURCE) all cargo packets from given source.
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:137
StringID name
Name of this type of cargo.
Definition cargotype.h:91
bool value
tells if the bool cheat is active or not
Definition cheat_type.h:18
Cheat magic_bulldozer
dynamite industries, objects
Definition cheat_type.h:27
SoundSettings sound
sound effect settings
uint8_t raw_industry_construction
type of (raw) industry construction (none, "normal", prospecting)
uint8_t industry_platform
the amount of flat land around an industry
uint8_t industry_density
The industry density.
This structure is the same for both Industries and Houses.
Definition sprite.h:76
This is used to gather some data about animation drawing in the industry code Image_1-2-3 are in fact...
uint8_t image_1
image offset 1
uint8_t image_3
image offset 3
uint8_t image_2
image offset 2
int x
coordinate x of the first image offset
EconomyType type
economy type (original/smooth/frozen)
bool multiple_industry_per_town
allow many industries of the same type per town
uint32_t industry_daily_change_counter
Bits 31-16 are number of industry to be performed, 15-0 are fractional collected daily.
uint32_t industry_daily_increment
The value which will increment industry_daily_change_counter. Computed value. NOSAVE.
A special vehicle is one of the following:
uint8_t animation_substate
Sub state to time the change of the graphics/behaviour.
const struct SpriteGroup * GetSpriteGroup(size_t index=0) const
Get the SpriteGroup at the specified index.
std::string GetName() const
Get the name of this grf.
const struct GRFFile * grffile
grf file that introduced this entity
uint32_t grfid
grfid that introduced this entity.
bool HasGrfFile() const
Test if this entity was introduced by NewGRF.
uint16_t custom_industry_number
manually entered number of industries
LandscapeType landscape
the landscape we're currently in
uint8_t oil_refinery_limit
distance oil refineries allowed from map edge
uint8_t land_generator
the landscape generator
EconomySettings economy
settings to change the economy
ConstructionSettings construction
construction of things in-game
DifficultySettings difficulty
settings related to the difficulty
GameCreationSettings game_creation
settings used during the creation of a game (map)
StationSettings station
settings related to station management
Data for managing the number and type of industries in the game.
Definition industry.h:290
void Reset()
Completely reset the industry build data.
void EconomyMonthlyLoop()
Monthly update of industry build data.
uint32_t wanted_inds
Number of wanted industries (bits 31-16), and a fraction (bits 15-0).
Definition industry.h:292
void SetupTargetCount()
Decide how many industries of each type are needed.
void TryBuildNewIndustry()
Try to create a random industry, during gameplay.
IndustryTypeBuildData builddata[NUM_INDUSTRYTYPES]
Industry build data for every industry type.
Definition industry.h:291
Defines the data structure for constructing industry.
IndustryCallbackMasks callback_mask
Bitmask of industry callbacks that have to be called.
bool IsProcessingIndustry() const
Is an industry with the spec a processing industry?
std::vector< uint8_t > random_sounds
Random sounds;.
Money GetRemovalCost() const
Get the cost for removing this industry Take note that the cost will always be zero for non-grf indus...
std::array< CargoType, INDUSTRY_NUM_INPUTS > accepts_cargo
16 accepted cargoes.
uint8_t appear_creation[NUM_LANDSCAPE]
Probability of appearance during map creation.
bool UsesOriginalEconomy() const
Determines whether this industrytype uses standard/newgrf production changes.
uint8_t minimal_cargo
minimum amount of cargo transported to the stations.
uint32_t removal_cost_multiplier
Base removal cost multiplier.
uint32_t prospecting_chance
Chance prospecting succeeds.
StringID production_up_text
Message appearing when the industry's production is increasing.
StringID name
Displayed name of the industry.
uint8_t cost_multiplier
Base construction cost multiplier.
bool IsRawIndustry() const
Is an industry with the spec a raw industry?
IndustryType conflicting[3]
Industries this industry cannot be close to.
uint8_t appear_ingame[NUM_LANDSCAPE]
Probability of appearance in game.
GRFFileProps grf_prop
properties related to the grf file
StringID production_down_text
Message appearing when the industry's production is decreasing.
IndustryBehaviours behaviour
How this industry will behave, and how others entities can use it.
StringID closure_text
Message appearing when the industry closes.
StringID new_industry_text
Message appearing when the industry is built.
std::vector< IndustryTileLayout > layouts
List of possible tile layouts for the industry.
bool enabled
entity still available (by default true).newgrf can disable it, though
Money GetConstructionCost() const
Get the cost for constructing this industry.
IndustryLifeTypes life_type
This is also known as Industry production flag, in newgrf specs.
uint8_t check_proc
Index to a procedure to check for conflicting circumstances.
Definition of one tile in an industry tile layout.
Defines the data structure of each individual tile of an industry.
uint8_t anim_next
Next frame in an animation.
IndustryTileSpecialFlags special_flags
Bitmask of extra flags used by the tile.
GRFFileProps grf_prop
properties related to the grf file
Slope slopes_refused
slope pattern on which this tile cannot be built
AnimationInfo animation
Information about the animation (is it looping, how many loops etc)
std::array< int8_t, INDUSTRY_NUM_INPUTS > acceptance
Level of acceptance per cargo type (signed, may be negative!)
bool anim_state
When true, the tile has to be drawn using the animation state instead of the construction state.
IndustryTileCallbackMasks callback_mask
Bitmask of industry tile callbacks that have to be called.
std::array< CargoType, INDUSTRY_NUM_INPUTS > accepts_cargo
Cargo accepted by this tile.
uint8_t anim_production
Animation frame to start when goods are produced.
Data for managing the number of industries of a single industry type.
Definition industry.h:275
uint32_t probability
Relative probability of building this industry.
Definition industry.h:276
uint16_t target_count
Desired number of industries of this type.
Definition industry.h:278
uint8_t min_number
Smallest number of industries that should exist (either 0 or 1).
Definition industry.h:277
void Reset()
Reset the entry.
bool GetIndustryTypeData(IndustryType it)
Set the probability and min_number fields for the industry type it for a running game.
uint16_t wait_count
Number of turns to wait before trying to build again.
Definition industry.h:280
uint16_t max_wait
Starting number of turns to wait (copied to wait_count).
Definition industry.h:279
CargoType cargo
Cargo type.
Definition industry.h:83
std::array< ProducedHistory, 25 > history
History of cargo produced and transported for this month and 24 previous months.
Definition industry.h:79
CargoType cargo
Cargo type.
Definition industry.h:76
uint8_t rate
Production rate.
Definition industry.h:78
Defines the internal data of a functional industry.
Definition industry.h:63
static Industry * GetRandom()
Return a random valid industry.
IndustryType type
type of industry.
Definition industry.h:99
Owner exclusive_supplier
Which company has exclusive rights to deliver cargo (INVALID_OWNER = anyone)
Definition industry.h:114
TimerGameCalendar::Date construction_date
Date of the construction of the industry.
Definition industry.h:111
IndustryControlFlags ctlflags
flags overriding standard behaviours
Definition industry.h:104
bool IsCargoAccepted() const
Test if this industry accepts any cargo.
Definition industry.h:207
PersistentStorage * psa
Persistent storage for NewGRF industries.
Definition industry.h:120
uint8_t prod_level
general production level
Definition industry.h:96
Colours random_colour
randomized colour of the industry, for display purpose
Definition industry.h:101
void RecomputeProductionMultipliers()
Recompute #production_rate for current prod_level.
EncodedString text
General text with additional information.
Definition industry.h:116
uint8_t construction_type
Way the industry was constructed (.
Definition industry.h:112
std::string cached_name
NOSAVE: Cache of the resolved name of the industry.
Definition industry.h:108
const ProducedCargo & GetProduced(size_t slot) const
Safely get a produced cargo slot, or an empty data if the slot does not exist.
Definition industry.h:142
TimerGameEconomy::Year last_prod_year
last economy year of production
Definition industry.h:102
ProducedCargoes produced
produced cargo slots
Definition industry.h:94
uint16_t random
Random value used for randomisation of all kinds of things.
Definition industry.h:118
static void PostDestructor(size_t index)
Invalidating some stuff after removing item from the pool.
Town * town
Nearest town.
Definition industry.h:92
Owner founder
Founder of the industry.
Definition industry.h:110
uint8_t selected_layout
Which tile layout was used when creating the industry.
Definition industry.h:113
AcceptedCargoes accepted
accepted cargo slots
Definition industry.h:95
static uint16_t GetIndustryTypeCount(IndustryType type)
Get the count of industries for this type.
Definition industry.h:248
Owner owner
owner of the industry. Which SHOULD always be (imho) OWNER_NONE
Definition industry.h:100
static Industry * GetByTile(TileIndex tile)
Get the industry of the given tile.
Definition industry.h:235
static std::array< std::vector< IndustryID >, NUM_INDUSTRYTYPES > industries
List of industries of each type.
Definition industry.h:260
TileArea location
Location of the industry.
Definition industry.h:91
Station * neutral_station
Associated neutral station.
Definition industry.h:93
StationList stations_near
NOSAVE: List of nearby stations.
Definition industry.h:107
bool IsCargoProduced() const
Test if this industry produces any cargo.
Definition industry.h:213
Owner exclusive_consumer
Which company has exclusive rights to take cargo (INVALID_OWNER = anyone)
Definition industry.h:115
uint16_t counter
used for animation and/or production (if available cargo)
Definition industry.h:97
uint8_t was_cargo_delivered
flag that indicate this has been the closest industry chosen for cargo delivery by a station....
Definition industry.h:103
bool TileBelongsToIndustry(TileIndex tile) const
Check if a given tile belongs to this industry.
Definition industry.h:132
static TileIndex WrapToMap(TileIndex tile)
'Wraps' the given "tile" so it is within the map.
Definition map_func.h:316
static uint ScaleBySize(uint n)
Scales the given value by the map size, where the given value is for a 256 by 256 map.
Definition map_func.h:327
static uint SizeY()
Get the size of the map along the Y.
Definition map_func.h:278
static debug_inline uint SizeX()
Get the size of the map along the X.
Definition map_func.h:269
static uint ScaleBySize1D(uint n)
Scales the given value by the maps circumference, where the given value is for a 256 by 256 map.
Definition map_func.h:340
static uint MaxY()
Gets the maximum Y coordinate within the map, including MP_VOID.
Definition map_func.h:305
static debug_inline uint Size()
Get the size of the map.
Definition map_func.h:287
static debug_inline uint MaxX()
Gets the maximum X coordinate within the map, including MP_VOID.
Definition map_func.h:296
Represents the covered area of e.g.
void ClampToMap()
Clamp the tile area to map borders.
Definition tilearea.cpp:142
uint16_t w
The width of the area.
void Add(TileIndex to_add)
Add a single tile to a tile area; enlarge if needed.
Definition tilearea.cpp:43
TileIndex tile
The base tile of the area.
uint16_t h
The height of the area.
OrthogonalTileArea & Expand(int rad)
Expand a tile area by rad tiles in each direction, keeping within map bounds.
Definition tilearea.cpp:123
SpriteID sprite
The 'real' sprite.
Definition gfx_type.h:23
PaletteID pal
The palette (use PAL_NONE) if not needed)
Definition gfx_type.h:24
Templated helper to make a PoolID a single POD value.
Definition pool_type.hpp:43
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static size_t GetPoolSize()
Returns first unused index.
static Titem * Get(auto index)
Returns Titem with given index.
static size_t GetNumItems()
Returns number of valid items in the pool.
Tindex index
Index of this pool item.
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
static bool CleaningPool()
Returns current state of pool cleaning - yes or no.
static Titem * GetIfValid(auto index)
Returns Titem with given index.
Base class for all pools.
static constexpr size_t MAX_SIZE
Make template parameter accessible from outside.
Structure to encapsulate the pseudo random number generators.
void SetSeed(uint32_t seed)
(Re)set the state of the random number generator.
uint32_t Next()
Generate the next pseudo random number.
bool ambient
Play ambient, industry and town sounds.
A location from where cargo can come from (or go to).
Definition source_type.h:32
static Station * Get(auto index)
Gets station with given index.
T * Next() const
Get next vehicle in the chain.
bool serve_neutral_industries
company stations can serve industries with attached neutral stations
Station data structure.
IndustryList industries_near
Cached list of industries near the station that can accept cargo,.
Tile description for the 'land area information' tool.
Definition tile_cmd.h:52
std::optional< std::string > grf
newGRF used for the tile contents
Definition tile_cmd.h:63
StringID str
Description of the tile.
Definition tile_cmd.h:53
std::array< Owner, 4 > owner
Name of the owner(s)
Definition tile_cmd.h:55
uint64_t dparam
Parameter of the str string.
Definition tile_cmd.h:54
Tile information, used while rendering the tile.
Definition tile_cmd.h:43
int z
Height.
Definition tile_cmd.h:48
int x
X position of the tile in unit coordinates.
Definition tile_cmd.h:44
Slope tileh
Slope of the tile.
Definition tile_cmd.h:46
TileIndex tile
Tile index.
Definition tile_cmd.h:47
int y
Y position of the tile in unit coordinates.
Definition tile_cmd.h:45
Set of callback functions for performing tile operations of a given tile type.
Definition tile_cmd.h:159
uint32_t population
Current population of people.
Definition town.h:42
Town data structure.
Definition town.h:52
TileIndex xy
town center tile
Definition town.h:53
TownCache cache
Container for all cacheable data.
Definition town.h:55
Vehicle data structure.
CargoType cargo_type
type of cargo this vehicle is carrying
debug_inline bool IsFrontEngine() const
Check if the vehicle is a front engine.
IterateWrapper Orders() const
Returns an iterable ensemble of orders of a vehicle.
Owner owner
Which company owns the vehicle?
void DeleteSubsidyWith(Source source)
Delete the subsidies associated with a given cargo source type and id.
Definition subsidy.cpp:119
Functions related to subsidies.
Command definitions related to terraforming.
bool IsTileFlat(TileIndex tile, int *h)
Check if a given tile is flat.
Definition tile_map.cpp:95
int GetTileMaxZ(TileIndex t)
Get top height of the tile inside the map.
Definition tile_map.cpp:136
int GetTileZ(TileIndex tile)
Get bottom height of the tile.
Definition tile_map.cpp:116
int GetTileMaxPixelZ(TileIndex tile)
Get top height of the tile.
Definition tile_map.h:312
static debug_inline TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition tile_map.h:96
uint8_t GetAnimationFrame(Tile t)
Get the current animation frame.
Definition tile_map.h:250
bool IsValidTile(Tile tile)
Checks if a tile is valid.
Definition tile_map.h:161
TropicZone GetTropicZone(Tile tile)
Get the tropic zone.
Definition tile_map.h:238
void SetAnimationFrame(Tile t, uint8_t frame)
Set a new animation frame.
Definition tile_map.h:262
static debug_inline bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
Slope GetTileSlope(TileIndex tile)
Return the slope of a given tile inside the map.
Definition tile_map.h:279
static debug_inline uint TileHeight(Tile tile)
Returns the height of a tile.
Definition tile_map.h:29
static const uint TILE_SIZE
Tile size in world coordinates.
Definition tile_type.h:15
@ TROPICZONE_RAINFOREST
Rainforest tile.
Definition tile_type.h:79
@ TROPICZONE_DESERT
Tile is desert.
Definition tile_type.h:78
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
@ MP_TREES
Tile got trees.
Definition tile_type.h:52
@ MP_STATION
A tile of a station.
Definition tile_type.h:53
@ MP_CLEAR
A tile without any structures, i.e. grass, rocks, farm fields etc.
Definition tile_type.h:48
@ MP_HOUSE
A house by a town.
Definition tile_type.h:51
@ MP_INDUSTRY
Part of an industry.
Definition tile_type.h:56
@ MP_VOID
Invisible tiles at the SW and SE border.
Definition tile_type.h:55
OrthogonalTileArea TileArea
Shorthand for the much more common orthogonal tile area.
Definition of Interval and OneShot timers.
Definition of the game-calendar-timer.
Definition of the game-economy-timer.
Definition of the tick-based game-timer.
Base of the town class.
Town * ClosestTownFromTile(TileIndex tile, uint threshold)
Return the town closest (in distance or ownership) to a given tile, within a given threshold.
bool IsTransparencySet(TransparencyOption to)
Check if the transparency option bit is set and if we aren't in the game menu (there's never transpar...
bool IsInvisibilitySet(TransparencyOption to)
Check if the invisibility option bit is set and if we aren't in the game menu (there's never transpar...
@ TO_INDUSTRIES
industries
TransportType
Available types of transport.
Map accessors for tree tiles.
TreeGrowthStage GetTreeGrowth(Tile t)
Returns the tree growth stage.
Definition tree_map.h:195
TreeGround GetTreeGround(Tile t)
Returns the groundtype for tree tiles.
Definition tree_map.h:102
@ TREE_GROUND_SHORE
shore
Definition tree_map.h:56
@ Grown
Fully grown tree.
CommandCost EnsureNoVehicleOnGround(TileIndex tile)
Ensure there is no vehicle at the ground at the given position.
Definition vehicle.cpp:543
Functions related to vehicles.
@ VEH_ROAD
Road vehicle type.
@ VEH_AIRCRAFT
Aircraft vehicle type.
@ VEH_SHIP
Ship vehicle type.
@ VEH_TRAIN
Train vehicle type.
void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, int h, int dz, int z, bool transparent, int bb_offset_x, int bb_offset_y, int bb_offset_z, const SubSprite *sub)
Draw a (transparent) sprite at given coordinates with a given bounding box.
Definition viewport.cpp:663
void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool transparent, const SubSprite *sub, bool scale, bool relative)
Add a child sprite to a parent sprite.
Definition viewport.cpp:819
void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub, int extra_offs_x, int extra_offs_y)
Draws a ground sprite for the current tile.
Definition viewport.cpp:579
Functions related to (drawing on) viewports.
Functions related to water (management)
void TileLoop_Water(TileIndex tile)
Let a water tile floods its diagonal adjoining tiles called from tunnelbridge_cmd,...
bool IsTileOnWater(Tile t)
Tests if the tile was built on water.
Definition water_map.h:136
WaterClass
classes of water (for WATER_TILE_CLEAR water tile type).
Definition water_map.h:39
@ WATER_CLASS_INVALID
Used for industry tiles on land (also for oilrig if newgrf says so).
Definition water_map.h:43
bool HasTileWaterClass(Tile t)
Checks whether the tile has an waterclass associated.
Definition water_map.h:101
WaterClass GetWaterClass(Tile t)
Get the water class at a tile.
Definition water_map.h:112
bool IsWaterTile(Tile t)
Is it a water tile with plain water?
Definition water_map.h:190
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Definition window.cpp:1143
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
Mark window data of the window of a given class and specific window number as invalid (in need of re-...
Definition window.cpp:3224
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3106
Window functions not directly related to making/drawing windows.
@ WC_INDUSTRY_DIRECTORY
Industry directory; Window numbers:
@ WC_INDUSTRY_PRODUCTION
Industry production history graph; Window numbers:
@ WC_INDUSTRY_VIEW
Industry view; Window numbers:
@ WC_BUILD_INDUSTRY
Build industry; Window numbers: