OpenTTD Source 20260311-master-g511d3794ce
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "stdafx.h"
11#include "misc/history_type.hpp"
12#include "misc/history_func.hpp"
13#include "clear_map.h"
14#include "industry.h"
15#include "station_base.h"
16#include "landscape.h"
17#include "viewport_func.h"
18#include "command_func.h"
19#include "town.h"
20#include "news_func.h"
21#include "cheat_type.h"
22#include "company_base.h"
23#include "genworld.h"
24#include "tree_map.h"
25#include "newgrf_cargo.h"
26#include "newgrf_debug.h"
28#include "autoslope.h"
29#include "water.h"
30#include "strings_func.h"
31#include "window_func.h"
32#include "vehicle_func.h"
33#include "sound_func.h"
34#include "animated_tile_func.h"
35#include "effectvehicle_func.h"
36#include "effectvehicle_base.h"
37#include "ai/ai.hpp"
38#include "core/pool_func.hpp"
39#include "subsidy_func.h"
40#include "core/backup_type.hpp"
41#include "object_base.h"
42#include "game/game.hpp"
43#include "error.h"
44#include "string_func.h"
45#include "industry_cmd.h"
46#include "landscape_cmd.h"
47#include "terraform_cmd.h"
48#include "map_func.h"
49#include "timer/timer.h"
53
54#include "table/strings.h"
55#include "table/industry_land.h"
57
58#include "safeguards.h"
59
60IndustryPool _industry_pool("Industry");
62
63void ShowIndustryViewWindow(IndustryID industry);
64void BuildOilRig(TileIndex tile);
65
66static uint8_t _industry_sound_ctr;
67static TileIndex _industry_sound_tile;
68
69std::array<FlatSet<IndustryID>, NUM_INDUSTRYTYPES> Industry::industries;
70
71IndustrySpec _industry_specs[NUM_INDUSTRYTYPES];
72IndustryTileSpec _industry_tile_specs[NUM_INDUSTRYTILES];
74
75static int WhoCanServiceIndustry(Industry *ind);
76
84{
85 auto industry_insert = std::copy(std::begin(_origin_industry_specs), std::end(_origin_industry_specs), std::begin(_industry_specs));
86 std::fill(industry_insert, std::end(_industry_specs), IndustrySpec{});
87
88 /* Enable only the current climate industries */
89 for (auto it = std::begin(_industry_specs); it != industry_insert; ++it) {
90 it->enabled = it->climate_availability.Test(_settings_game.game_creation.landscape);
91 }
92
93 auto industry_tile_insert = std::copy(std::begin(_origin_industry_tile_specs), std::end(_origin_industry_tile_specs), std::begin(_industry_tile_specs));
94 std::fill(industry_tile_insert, std::end(_industry_tile_specs), IndustryTileSpec{});
95
96 /* Reset any overrides that have been set. */
97 _industile_mngr.ResetOverride();
98 _industry_mngr.ResetOverride();
99}
100
109IndustryType GetIndustryType(Tile tile)
110{
111 assert(IsTileType(tile, TileType::Industry));
112
113 const Industry *ind = Industry::GetByTile(tile);
114 assert(ind != nullptr);
115 return ind->type;
116}
117
126const IndustrySpec *GetIndustrySpec(IndustryType thistype)
127{
128 assert(thistype < NUM_INDUSTRYTYPES);
129 return &_industry_specs[thistype];
130}
131
141{
142 assert(gfx < NUM_INDUSTRYTILES);
143 return &_industry_tile_specs[gfx];
144}
145
148{
149 if (CleaningPool()) return;
150
151 /* Industry can also be destroyed when not fully initialized.
152 * This means that we do not have to clear tiles either.
153 * Also we must not decrement industry counts in that case. */
154 if (this->location.w == 0) return;
155
156 const bool has_neutral_station = this->neutral_station != nullptr;
157
158 for (TileIndex tile_cur : this->location) {
159 if (IsTileType(tile_cur, TileType::Industry)) {
160 if (GetIndustryIndex(tile_cur) == this->index) {
161 DeleteNewGRFInspectWindow(GSF_INDUSTRYTILES, tile_cur.base());
162
163 /* MakeWaterKeepingClass() can also handle 'land' */
164 MakeWaterKeepingClass(tile_cur, OWNER_NONE);
165 }
166 } else if (IsTileType(tile_cur, TileType::Station) && IsOilRig(tile_cur)) {
167 DeleteOilRig(tile_cur);
168 }
169 }
170
171 if (has_neutral_station) {
172 /* Remove possible docking tiles */
173 for (TileIndex tile_cur : this->location) {
175 }
176 }
177
178 if (GetIndustrySpec(this->type)->behaviour.Test(IndustryBehaviour::PlantFields)) {
179 TileArea ta = TileArea(this->location.tile, 0, 0).Expand(21);
180
181 /* Remove the farmland and convert it to regular tiles over time. */
182 for (TileIndex tile_cur : ta) {
183 if (IsTileType(tile_cur, TileType::Clear) && IsClearGround(tile_cur, ClearGround::Fields) &&
184 GetIndustryIndexOfField(tile_cur) == this->index) {
185 SetIndustryIndexOfField(tile_cur, IndustryID::Invalid());
186 }
187 }
188 }
189
190 /* don't let any disaster vehicle target invalid industry */
192
193 /* Clear the persistent storage. */
194 delete this->psa;
195
197 industries.erase(this->index);
198
202 DeleteNewGRFInspectWindow(GSF_INDUSTRIES, this->index);
203
207
208 for (Station *st : this->stations_near) {
209 st->RemoveIndustryToDeliver(this);
210 }
211}
212
218{
219 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, IDIWD_FORCE_REBUILD);
221}
222
223
228/* static */ Industry *Industry::GetRandom()
229{
230 if (Industry::GetNumItems() == 0) return nullptr;
231 int num = RandomRange((uint16_t)Industry::GetNumItems());
232 size_t index = std::numeric_limits<size_t>::max();
233
234 while (num >= 0) {
235 num--;
236 index++;
237
238 /* Make sure we have a valid industry */
239 while (!Industry::IsValidID(index)) {
240 index++;
241 assert(index < Industry::GetPoolSize());
242 }
243 }
244
245 return Industry::Get(index);
246}
247
248
249static void IndustryDrawSugarMine(const TileInfo *ti)
250{
251 if (!IsIndustryCompleted(ti->tile)) return;
252
254
255 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_SIEVE + d->image_1, PAL_NONE, d->x, 0);
256
257 if (d->image_2 != 0) {
258 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_CLOUDS + d->image_2 - 1, PAL_NONE, 8, 41);
259 }
260
261 if (d->image_3 != 0) {
262 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_PILE + d->image_3 - 1, PAL_NONE,
263 _drawtile_proc1[d->image_3 - 1].x, _drawtile_proc1[d->image_3 - 1].y);
264 }
265}
266
267static void IndustryDrawToffeeQuarry(const TileInfo *ti)
268{
269 uint8_t x = 0;
270
271 if (IsIndustryCompleted(ti->tile)) {
273 if (x == 0xFF) {
274 x = 0;
275 }
276 }
277
278 AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_SHOVEL, PAL_NONE, 22 - x, 24 + x);
279 AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_TOFFEE, PAL_NONE, 6, 14);
280}
281
282static void IndustryDrawBubbleGenerator( const TileInfo *ti)
283{
284 if (IsIndustryCompleted(ti->tile)) {
285 AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_BUBBLE, PAL_NONE, 5, _industry_anim_offs_bubbles[GetAnimationFrame(ti->tile)]);
286 }
287 AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_SPRING, PAL_NONE, 3, 67);
288}
289
290static void IndustryDrawToyFactory(const TileInfo *ti)
291{
292 const DrawIndustryAnimationStruct *d = &_industry_anim_offs_toys[GetAnimationFrame(ti->tile)];
293
294 if (d->image_1 != 0xFF) {
295 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_CLAY, PAL_NONE, d->x, 96 + d->image_1);
296 }
297
298 if (d->image_2 != 0xFF) {
299 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_ROBOT, PAL_NONE, 16 - d->image_2 * 2, 100 + d->image_2);
300 }
301
302 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP, PAL_NONE, 7, d->image_3);
303 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP_HOLDER, PAL_NONE, 0, 42);
304}
305
306static void IndustryDrawCoalPlantSparks(const TileInfo *ti)
307{
308 if (IsIndustryCompleted(ti->tile)) {
309 uint8_t image = GetAnimationFrame(ti->tile);
310
311 if (image != 0 && image < 7) {
312 AddChildSpriteScreen(image + SPR_IT_POWER_PLANT_TRANSFORMERS,
313 PAL_NONE,
314 _coal_plant_sparks[image - 1].x,
315 _coal_plant_sparks[image - 1].y
316 );
317 }
318 }
319}
320
321typedef void IndustryDrawTileProc(const TileInfo *ti);
322static IndustryDrawTileProc * const _industry_draw_tile_procs[5] = {
323 IndustryDrawSugarMine,
324 IndustryDrawToffeeQuarry,
325 IndustryDrawBubbleGenerator,
326 IndustryDrawToyFactory,
327 IndustryDrawCoalPlantSparks,
328};
329
332{
333 IndustryGfx gfx = GetIndustryGfx(ti->tile);
335 const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
336
337 /* Retrieve pointer to the draw industry tile struct */
338 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
339 /* Draw the tile using the specialized method of newgrf industrytile.
340 * DrawNewIndustry will return false if ever the resolver could not
341 * find any sprite to display. So in this case, we will jump on the
342 * substitute gfx instead. */
343 if (indts->grf_prop.HasSpriteGroups() && DrawNewIndustryTile(ti, ind, gfx, indts)) {
344 return;
345 } else {
346 /* No sprite group (or no valid one) found, meaning no graphics associated.
347 * Use the substitute one instead */
348 if (indts->grf_prop.subst_id != INVALID_INDUSTRYTILE) {
349 gfx = indts->grf_prop.subst_id;
350 /* And point the industrytile spec accordingly */
351 indts = GetIndustryTileSpec(gfx);
352 }
353 }
354 }
355
356 const DrawBuildingsTileStruct *dits = &_industry_draw_tile_data[gfx << 2 | (indts->anim_state ?
359
360 SpriteID image = dits->ground.sprite;
361
362 /* DrawFoundation() modifies ti->z and ti->tileh */
364
365 /* If the ground sprite is the default flat water sprite, draw also canal/river borders.
366 * Do not do this if the tile's WaterClass is 'land'. */
367 if (image == SPR_FLAT_WATER_TILE && IsTileOnWater(ti->tile)) {
368 DrawWaterClassGround(ti);
369 } else {
371 }
372
373 /* If industries are transparent and invisible, do not draw the upper part */
374 if (IsInvisibilitySet(TO_INDUSTRIES)) return;
375
376 /* Add industry on top of the ground? */
377 image = dits->building.sprite;
378 if (image != 0) {
380 *ti, *dits, IsTransparencySet(TO_INDUSTRIES));
381
382 if (IsTransparencySet(TO_INDUSTRIES)) return;
383 }
384
385 {
386 int proc = dits->draw_proc - 1;
387 if (proc >= 0) _industry_draw_tile_procs[proc](ti);
388 }
389}
390
393{
394 IndustryGfx gfx = GetIndustryGfx(tile);
395
396 /* For NewGRF industry tiles we might not be drawing a foundation. We need to
397 * account for this, as other structures should
398 * draw the wall of the foundation in this case.
399 */
400 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
401 const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
403 uint32_t callback_res = GetIndustryTileCallback(CBID_INDTILE_DRAW_FOUNDATIONS, 0, 0, gfx, Industry::GetByTile(tile), tile);
404 if (callback_res != CALLBACK_FAILED && !ConvertBooleanCallback(indts->grf_prop.grffile, CBID_INDTILE_DRAW_FOUNDATIONS, callback_res)) return FOUNDATION_NONE;
405 }
406 }
407 return FlatteningFoundation(tileh);
408}
409
411static void AddAcceptedCargo_Industry(TileIndex tile, CargoArray &acceptance, CargoTypes &always_accepted)
412{
413 IndustryGfx gfx = GetIndustryGfx(tile);
414 const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
415 const Industry *ind = Industry::GetByTile(tile);
416
417 /* Starting point for acceptance */
418 auto accepts_cargo = itspec->accepts_cargo;
419 auto cargo_acceptance = itspec->acceptance;
420
422 /* Copy all accepted cargoes from industry itself */
423 for (const auto &a : ind->accepted) {
424 auto pos = std::ranges::find(accepts_cargo, a.cargo);
425 if (pos == std::end(accepts_cargo)) {
426 /* Not found, insert */
427 pos = std::ranges::find(accepts_cargo, INVALID_CARGO);
428 if (pos == std::end(accepts_cargo)) continue; // nowhere to place, give up on this one
429 *pos = a.cargo;
430 }
431 cargo_acceptance[std::distance(std::begin(accepts_cargo), pos)] += 8;
432 }
433 }
434
436 /* Try callback for accepts list, if success override all existing accepts */
437 uint16_t res = GetIndustryTileCallback(CBID_INDTILE_ACCEPT_CARGO, 0, 0, gfx, Industry::GetByTile(tile), tile);
438 if (res != CALLBACK_FAILED) {
439 accepts_cargo.fill(INVALID_CARGO);
440 for (uint i = 0; i < INDUSTRY_ORIGINAL_NUM_INPUTS; i++) accepts_cargo[i] = GetCargoTranslation(GB(res, i * 5, 5), itspec->grf_prop.grffile);
441 }
442 }
443
445 /* Try callback for acceptance list, if success override all existing acceptance */
446 uint16_t res = GetIndustryTileCallback(CBID_INDTILE_CARGO_ACCEPTANCE, 0, 0, gfx, Industry::GetByTile(tile), tile);
447 if (res != CALLBACK_FAILED) {
448 cargo_acceptance.fill(0);
449 for (uint i = 0; i < INDUSTRY_ORIGINAL_NUM_INPUTS; i++) cargo_acceptance[i] = GB(res, i * 4, 4);
450 }
451 }
452
453 for (size_t i = 0; i < std::size(itspec->accepts_cargo); i++) {
454 CargoType cargo = accepts_cargo[i];
455 if (!IsValidCargoType(cargo) || cargo_acceptance[i] <= 0) continue; // work only with valid cargoes
456
457 /* Add accepted cargo */
458 acceptance[cargo] += cargo_acceptance[i];
459
460 /* Maybe set 'always accepted' bit (if it's not set already) */
461 if (HasBit(always_accepted, cargo)) continue;
462
463 /* Test whether the industry itself accepts the cargo type */
464 if (ind->IsCargoAccepted(cargo)) continue;
465
466 /* If the industry itself doesn't accept this cargo, set 'always accepted' bit */
467 SetBit(always_accepted, cargo);
468 }
469}
470
473{
474 const Industry *i = Industry::GetByTile(tile);
475 const IndustrySpec *is = GetIndustrySpec(i->type);
476
477 td.owner[0] = i->owner;
478 td.str = is->name;
479 if (!IsIndustryCompleted(tile)) {
480 td.dparam = td.str;
481 td.str = STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION;
482 }
483
484 if (is->grf_prop.HasGrfFile()) {
486 }
487}
488
490static CommandCost ClearTile_Industry(TileIndex tile, DoCommandFlags flags)
491{
492 Industry *i = Industry::GetByTile(tile);
493 const IndustrySpec *indspec = GetIndustrySpec(i->type);
494
495 /* water can destroy industries
496 * in editor you can bulldoze industries
497 * with magic_bulldozer cheat you can destroy industries
498 * (area around OILRIG is water, so water shouldn't flood it
499 */
500 if ((_current_company != OWNER_WATER && _game_mode != GM_EDITOR &&
501 !_cheats.magic_bulldozer.value) ||
502 flags.Test(DoCommandFlag::Auto) ||
505 HasBit(GetIndustryTileSpec(GetIndustryGfx(tile))->slopes_refused, 5)))) {
506
507 if (flags.Test(DoCommandFlag::Auto)) {
508 return CommandCostWithParam(STR_ERROR_GENERIC_OBJECT_IN_THE_WAY, indspec->name);
509 }
511 }
512
513 if (flags.Test(DoCommandFlag::Execute)) {
514 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index));
515 Game::NewEvent(new ScriptEventIndustryClose(i->index));
516 delete i;
517 }
519}
520
527{
528 Industry *i = Industry::GetByTile(tile);
529 const IndustrySpec *indspec = GetIndustrySpec(i->type);
530 bool moved_cargo = false;
531
532 for (auto &p : i->produced) {
533 uint cw = ClampTo<uint8_t>(p.waiting);
534 if (cw > indspec->minimal_cargo && IsValidCargoType(p.cargo)) {
535 p.waiting -= cw;
536
537 /* fluctuating economy? */
538 if (EconomyIsInRecession()) cw = (cw + 1) / 2;
539
540 p.history[THIS_MONTH].production += cw;
541
542 uint am = MoveGoodsToStation(p.cargo, cw, {i->index, SourceType::Industry}, i->stations_near, i->exclusive_consumer);
543 p.history[THIS_MONTH].transported += am;
544
545 moved_cargo |= (am != 0);
546 }
547 }
548
549 return moved_cargo;
550}
551
552static void AnimateSugarSieve(TileIndex tile)
553{
554 uint8_t m = GetAnimationFrame(tile) + 1;
555
556 if (_settings_client.sound.ambient) {
557 switch (m & 7) {
558 case 2: SndPlayTileFx(SND_2D_SUGAR_MINE_1, tile); break;
559 case 6: SndPlayTileFx(SND_29_SUGAR_MINE_2, tile); break;
560 }
561 }
562
563 if (m >= 96) {
564 m = 0;
565 DeleteAnimatedTile(tile);
566 }
567 SetAnimationFrame(tile, m);
568
570}
571
572static void AnimateToffeeQuarry(TileIndex tile)
573{
574 uint8_t m = GetAnimationFrame(tile);
575
576 if (_industry_anim_offs_toffee[m] == 0xFF && _settings_client.sound.ambient) {
577 SndPlayTileFx(SND_30_TOFFEE_QUARRY, tile);
578 }
579
580 if (++m >= 70) {
581 m = 0;
582 DeleteAnimatedTile(tile);
583 }
584 SetAnimationFrame(tile, m);
585
587}
588
589static void AnimateBubbleCatcher(TileIndex tile)
590{
591 uint8_t m = GetAnimationFrame(tile);
592
593 if (++m >= 40) {
594 m = 0;
595 DeleteAnimatedTile(tile);
596 }
597 SetAnimationFrame(tile, m);
598
600}
601
602static void AnimatePowerPlantSparks(TileIndex tile)
603{
604 uint8_t m = GetAnimationFrame(tile);
605 if (m == 6) {
606 SetAnimationFrame(tile, 0);
607 DeleteAnimatedTile(tile);
608 } else {
609 SetAnimationFrame(tile, m + 1);
610 }
612}
613
614static void AnimateToyFactory(TileIndex tile)
615{
616 uint8_t m = GetAnimationFrame(tile) + 1;
617
618 switch (m) {
619 case 1: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2C_TOY_FACTORY_1, tile); break;
620 case 23: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2B_TOY_FACTORY_2, tile); break;
621 case 28: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2A_TOY_FACTORY_3, tile); break;
622 default:
623 if (m >= 50) {
624 int n = GetIndustryAnimationLoop(tile) + 1;
625 m = 0;
626 if (n >= 8) {
627 n = 0;
628 DeleteAnimatedTile(tile);
629 }
631 }
632 }
633
634 SetAnimationFrame(tile, m);
636}
637
638static void AnimatePlasticFountain(TileIndex tile, IndustryGfx gfx)
639{
640 gfx = (gfx < GFX_PLASTIC_FOUNTAIN_ANIMATED_8) ? gfx + 1 : GFX_PLASTIC_FOUNTAIN_ANIMATED_1;
641 SetIndustryGfx(tile, gfx);
643}
644
645static void AnimateOilWell(TileIndex tile, IndustryGfx gfx)
646{
647 bool b = Chance16(1, 7);
648 uint8_t m = GetAnimationFrame(tile) + 1;
649 if (m == 4 && (m = 0, ++gfx) == GFX_OILWELL_ANIMATED_3 + 1 && (gfx = GFX_OILWELL_ANIMATED_1, b)) {
650 SetIndustryGfx(tile, GFX_OILWELL_NOT_ANIMATED);
652 DeleteAnimatedTile(tile);
653 } else {
654 SetAnimationFrame(tile, m);
655 SetIndustryGfx(tile, gfx);
656 }
658}
659
660static void AnimateMineTower(TileIndex tile)
661{
662 int state = TimerGameTick::counter & 0x7FF;
663
664 if ((state -= 0x400) < 0) return;
665
666 if (state < 0x1A0) {
667 if (state < 0x20 || state >= 0x180) {
668 uint8_t m = GetAnimationFrame(tile);
669 if (!(m & 0x40)) {
670 SetAnimationFrame(tile, m | 0x40);
671 if (_settings_client.sound.ambient) SndPlayTileFx(SND_0B_MINE, tile);
672 }
673 if (state & 7) return;
674 } else {
675 if (state & 3) return;
676 }
677 uint8_t m = (GetAnimationFrame(tile) + 1) | 0x40;
678 if (m > 0xC2) m = 0xC0;
679 SetAnimationFrame(tile, m);
681 } else if (state >= 0x200 && state < 0x3A0) {
682 int i = (state < 0x220 || state >= 0x380) ? 7 : 3;
683 if (state & i) return;
684
685 uint8_t m = (GetAnimationFrame(tile) & 0xBF) - 1;
686 if (m < 0x80) m = 0x82;
687 SetAnimationFrame(tile, m);
689 }
690}
691
694{
695 IndustryGfx gfx = GetIndustryGfx(tile);
696
697 if (GetIndustryTileSpec(gfx)->animation.status != AnimationStatus::NoAnimation) {
698 AnimateNewIndustryTile(tile);
699 return;
700 }
701
702 switch (gfx) {
703 case GFX_SUGAR_MINE_SIEVE:
704 if ((TimerGameTick::counter & 1) == 0) AnimateSugarSieve(tile);
705 break;
706
707 case GFX_TOFFEE_QUARRY:
708 if ((TimerGameTick::counter & 3) == 0) AnimateToffeeQuarry(tile);
709 break;
710
711 case GFX_BUBBLE_CATCHER:
712 if ((TimerGameTick::counter & 1) == 0) AnimateBubbleCatcher(tile);
713 break;
714
715 case GFX_POWERPLANT_SPARKS:
716 if ((TimerGameTick::counter & 3) == 0) AnimatePowerPlantSparks(tile);
717 break;
718
719 case GFX_TOY_FACTORY:
720 if ((TimerGameTick::counter & 1) == 0) AnimateToyFactory(tile);
721 break;
722
723 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
724 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
725 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
726 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
727 if ((TimerGameTick::counter & 3) == 0) AnimatePlasticFountain(tile, gfx);
728 break;
729
730 case GFX_OILWELL_ANIMATED_1:
731 case GFX_OILWELL_ANIMATED_2:
732 case GFX_OILWELL_ANIMATED_3:
733 if ((TimerGameTick::counter & 7) == 0) AnimateOilWell(tile, gfx);
734 break;
735
736 case GFX_COAL_MINE_TOWER_ANIMATED:
737 case GFX_COPPER_MINE_TOWER_ANIMATED:
738 case GFX_GOLD_MINE_TOWER_ANIMATED:
739 AnimateMineTower(tile);
740 break;
741 }
742}
743
744static void CreateChimneySmoke(TileIndex tile)
745{
746 uint x = TileX(tile) * TILE_SIZE;
747 uint y = TileY(tile) * TILE_SIZE;
748 int z = GetTileMaxPixelZ(tile);
749
750 CreateEffectVehicle(x + 15, y + 14, z + 59, EV_CHIMNEY_SMOKE);
751}
752
753static void MakeIndustryTileBigger(TileIndex tile)
754{
755 uint8_t cnt = GetIndustryConstructionCounter(tile) + 1;
756 if (cnt != 4) {
758 return;
759 }
760
761 uint8_t stage = GetIndustryConstructionStage(tile) + 1;
763 SetIndustryConstructionStage(tile, stage);
764 TriggerIndustryTileAnimation_ConstructionStageChanged(tile, false);
765 if (stage == INDUSTRY_COMPLETED) SetIndustryCompleted(tile);
766
768
769 if (!IsIndustryCompleted(tile)) return;
770
771 IndustryGfx gfx = GetIndustryGfx(tile);
772 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
773 /* New industries are already animated on construction. */
774 return;
775 }
776
777 switch (gfx) {
778 case GFX_POWERPLANT_CHIMNEY:
779 CreateChimneySmoke(tile);
780 break;
781
782 case GFX_OILRIG_1: {
783 /* Do not require an industry tile to be after the first two GFX_OILRIG_1
784 * tiles (like the default oil rig). Do a proper check to ensure the
785 * tiles belong to the same industry and based on that build the oil rig's
786 * station. */
787 TileIndex other = tile + TileDiffXY(0, 1);
788
789 if (IsTileType(other, TileType::Industry) &&
790 GetIndustryGfx(other) == GFX_OILRIG_1 &&
791 GetIndustryIndex(tile) == GetIndustryIndex(other)) {
792 BuildOilRig(tile);
793 }
794 break;
795 }
796
797 case GFX_TOY_FACTORY:
798 case GFX_BUBBLE_CATCHER:
799 case GFX_TOFFEE_QUARRY:
800 SetAnimationFrame(tile, 0);
802 break;
803
804 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
805 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
806 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
807 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
808 AddAnimatedTile(tile, false);
809 break;
810 }
811}
812
813static void TileLoopIndustry_BubbleGenerator(TileIndex tile)
814{
815 static const int8_t _bubble_spawn_location[3][4] = {
816 { 11, 0, -4, -14 },
817 { -4, -10, -4, 1 },
818 { 49, 59, 60, 65 },
819 };
820
821 if (_settings_client.sound.ambient) SndPlayTileFx(SND_2E_BUBBLE_GENERATOR, tile);
822
823 int dir = Random() & 3;
824
826 TileX(tile) * TILE_SIZE + _bubble_spawn_location[0][dir],
827 TileY(tile) * TILE_SIZE + _bubble_spawn_location[1][dir],
828 _bubble_spawn_location[2][dir],
830 );
831
832 if (v != nullptr) v->animation_substate = dir;
833}
834
837{
838 if (IsTileOnWater(tile)) TileLoop_Water(tile);
839
840 /* Normally this doesn't happen, but if an industry NewGRF is removed
841 * an industry that was previously build on water can now be flooded.
842 * If this happens the tile is no longer an industry tile after
843 * returning from TileLoop_Water. */
844 if (!IsTileType(tile, TileType::Industry)) return;
845
847
848 if (!IsIndustryCompleted(tile)) {
849 MakeIndustryTileBigger(tile);
850 return;
851 }
852
853 if (_game_mode == GM_EDITOR) return;
854
855 if (TransportIndustryGoods(tile) && !TriggerIndustryAnimation(Industry::GetByTile(tile), IndustryAnimationTrigger::CargoDistributed)) {
857
858 if (newgfx != INDUSTRYTILE_NOANIM) {
861 SetIndustryGfx(tile, newgfx);
863 return;
864 }
865 }
866
867 if (TriggerIndustryTileAnimation(tile, IndustryAnimationTrigger::TileLoop)) return;
868
869 IndustryGfx newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_next;
870 if (newgfx != INDUSTRYTILE_NOANIM) {
872 SetIndustryGfx(tile, newgfx);
874 return;
875 }
876
877 IndustryGfx gfx = GetIndustryGfx(tile);
878 switch (gfx) {
879 case GFX_COAL_MINE_TOWER_NOT_ANIMATED:
880 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED:
881 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED:
882 if (!(TimerGameTick::counter & 0x400) && Chance16(1, 2)) {
883 switch (gfx) {
884 case GFX_COAL_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COAL_MINE_TOWER_ANIMATED; break;
885 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_ANIMATED; break;
886 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_ANIMATED; break;
887 }
888 SetIndustryGfx(tile, gfx);
889 SetAnimationFrame(tile, 0x80);
890 AddAnimatedTile(tile);
891 }
892 break;
893
894 case GFX_OILWELL_NOT_ANIMATED:
895 if (Chance16(1, 6)) {
896 SetIndustryGfx(tile, GFX_OILWELL_ANIMATED_1);
897 SetAnimationFrame(tile, 0);
898 AddAnimatedTile(tile);
899 }
900 break;
901
902 case GFX_COAL_MINE_TOWER_ANIMATED:
903 case GFX_COPPER_MINE_TOWER_ANIMATED:
904 case GFX_GOLD_MINE_TOWER_ANIMATED:
905 if (!(TimerGameTick::counter & 0x400)) {
906 switch (gfx) {
907 case GFX_COAL_MINE_TOWER_ANIMATED: gfx = GFX_COAL_MINE_TOWER_NOT_ANIMATED; break;
908 case GFX_COPPER_MINE_TOWER_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_NOT_ANIMATED; break;
909 case GFX_GOLD_MINE_TOWER_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_NOT_ANIMATED; break;
910 }
911 SetIndustryGfx(tile, gfx);
914 DeleteAnimatedTile(tile);
916 }
917 break;
918
919 case GFX_POWERPLANT_SPARKS:
920 if (Chance16(1, 3)) {
921 if (_settings_client.sound.ambient) SndPlayTileFx(SND_0C_POWER_STATION, tile);
922 AddAnimatedTile(tile);
923 }
924 break;
925
926 case GFX_COPPER_MINE_CHIMNEY:
928 break;
929
930
931 case GFX_TOY_FACTORY: {
932 Industry *i = Industry::GetByTile(tile);
933 if (i->was_cargo_delivered) {
934 i->was_cargo_delivered = false;
936 AddAnimatedTile(tile);
937 }
938 }
939 break;
940
941 case GFX_BUBBLE_GENERATOR:
942 TileLoopIndustry_BubbleGenerator(tile);
943 break;
944
945 case GFX_TOFFEE_QUARRY:
946 AddAnimatedTile(tile);
947 break;
948
949 case GFX_SUGAR_MINE_SIEVE:
950 if (Chance16(1, 3)) AddAnimatedTile(tile);
951 break;
952 }
953}
954
957{
958 ShowIndustryViewWindow(GetIndustryIndex(tile));
959 return true;
960}
961
963static void ChangeTileOwner_Industry(TileIndex tile, Owner old_owner, Owner new_owner)
964{
965 /* If the founder merges, the industry was created by the merged company */
966 Industry *i = Industry::GetByTile(tile);
967 if (i->founder == old_owner) i->founder = (new_owner == INVALID_OWNER) ? OWNER_NONE : new_owner;
968
969 if (i->exclusive_supplier == old_owner) i->exclusive_supplier = new_owner;
970 if (i->exclusive_consumer == old_owner) i->exclusive_consumer = new_owner;
971}
972
979{
980 /* Check for industry tile */
981 if (!IsTileType(tile, TileType::Industry)) return false;
982
983 const Industry *ind = Industry::GetByTile(tile);
984
985 /* Check for organic industry (i.e. not processing or extractive) */
987
988 /* Check for wood production */
989 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; });
990}
991
992static const uint8_t _plantfarmfield_type[] = {1, 1, 1, 1, 1, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6};
993
1001static bool IsSuitableForFarmField(TileIndex tile, bool allow_fields, bool allow_rough)
1002{
1003 switch (GetTileType(tile)) {
1004 case TileType::Clear:
1005 if (IsSnowTile(tile)) return false;
1006 switch (GetClearGround(tile)) {
1007 case ClearGround::Desert: return false;
1008 case ClearGround::Rough: return allow_rough;
1009 case ClearGround::Fields: return allow_fields;
1010 default: return true;
1011 }
1012 case TileType::Trees: return GetTreeGround(tile) != TreeGround::Shore && (allow_rough || GetTreeGround(tile) != TreeGround::Rough);
1013 default: return false;
1014 }
1015}
1016
1024static void SetupFarmFieldFence(TileIndex tile, int size, uint8_t type, DiagDirection side)
1025{
1027 TileIndexDiff neighbour_diff = TileOffsByDiagDir(side);
1028
1029 do {
1030 tile = Map::WrapToMap(tile);
1031
1033 TileIndex neighbour = tile + neighbour_diff;
1034 if (!IsTileType(neighbour, TileType::Clear) || !IsClearGround(neighbour, ClearGround::Fields) || GetFence(neighbour, ReverseDiagDir(side)) == 0) {
1035 /* Add fence as long as neighbouring tile does not already have a fence in the same position. */
1036 uint8_t or_ = type;
1037
1038 if (or_ == 1 && Chance16(1, 7)) or_ = 2;
1039
1040 SetFence(tile, side, or_);
1041 }
1042 }
1043
1044 tile += diff;
1045 } while (--size);
1046}
1047
1048static void PlantFarmField(TileIndex tile, IndustryID industry)
1049{
1050 if (_settings_game.game_creation.landscape == LandscapeType::Arctic) {
1051 if (GetTileZ(tile) + 2 >= GetSnowLine()) return;
1052 }
1053
1054 /* determine field size */
1055 uint32_t r = (Random() & 0x303) + 0x404;
1056 if (_settings_game.game_creation.landscape == LandscapeType::Arctic) r += 0x404;
1057 uint size_x = GB(r, 0, 8);
1058 uint size_y = GB(r, 8, 8);
1059
1060 TileArea ta(tile - TileDiffXY(std::min(TileX(tile), size_x / 2), std::min(TileY(tile), size_y / 2)), size_x, size_y);
1061 ta.ClampToMap();
1062
1063 if (ta.w == 0 || ta.h == 0) return;
1064
1065 /* check the amount of bad tiles */
1066 int count = 0;
1067 for (TileIndex cur_tile : ta) {
1068 assert(cur_tile < Map::Size());
1069 count += IsSuitableForFarmField(cur_tile, false, false);
1070 }
1071 if (count * 2 < ta.w * ta.h) return;
1072
1073 /* determine type of field */
1074 r = Random();
1075 uint counter = GB(r, 5, 3);
1076 uint field_type = GB(r, 8, 8) * 9 >> 8;
1077
1078 /* make field */
1079 for (TileIndex cur_tile : ta) {
1080 assert(cur_tile < Map::Size());
1081 if (IsSuitableForFarmField(cur_tile, true, true)) {
1082 MakeField(cur_tile, field_type, industry);
1083 SetClearCounter(cur_tile, counter);
1084 MarkTileDirtyByTile(cur_tile);
1085 }
1086 }
1087
1088 int type = 3;
1089 if (_settings_game.game_creation.landscape != LandscapeType::Arctic && _settings_game.game_creation.landscape != LandscapeType::Tropic) {
1090 type = _plantfarmfield_type[Random() & 0xF];
1091 }
1092
1093 SetupFarmFieldFence(ta.tile, ta.h, type, DIAGDIR_NE);
1094 SetupFarmFieldFence(ta.tile, ta.w, type, DIAGDIR_NW);
1095 SetupFarmFieldFence(ta.tile + TileDiffXY(ta.w - 1, 0), ta.h, type, DIAGDIR_SW);
1096 SetupFarmFieldFence(ta.tile + TileDiffXY(0, ta.h - 1), ta.w, type, DIAGDIR_SE);
1097}
1098
1099void PlantRandomFarmField(const Industry *i)
1100{
1101 int x = i->location.w / 2 + Random() % 31 - 16;
1102 int y = i->location.h / 2 + Random() % 31 - 16;
1103
1104 TileIndex tile = TileAddWrap(i->location.tile, x, y);
1105
1106 if (tile != INVALID_TILE) PlantFarmField(tile, i->index);
1107}
1108
1114{
1115 /* Don't process lumber mill if cargo is not set up correctly. */
1116 auto itp = std::begin(i->produced);
1117 if (itp == std::end(i->produced) || !IsValidCargoType(itp->cargo)) return;
1118
1119 /* We only want to cut trees if all tiles are completed. */
1120 for (TileIndex tile_cur : i->location) {
1121 if (i->TileBelongsToIndustry(tile_cur)) {
1122 if (!IsIndustryCompleted(tile_cur)) return;
1123 }
1124 }
1125
1126 for (auto tile : SpiralTileSequence(i->location.tile, 40)) { // 40x40 tiles to search.
1127 if (!IsTileType(tile, TileType::Trees) || GetTreeGrowth(tile) < TreeGrowthStage::Grown) continue;
1128
1129 /* found a tree */
1130 _industry_sound_ctr = 1;
1131 _industry_sound_tile = tile;
1132 if (_settings_client.sound.ambient) SndPlayTileFx(SND_38_LUMBER_MILL_1, tile);
1133
1135 Command<Commands::LandscapeClear>::Do(DoCommandFlag::Execute, tile);
1136
1137 /* Add according value to waiting cargo. */
1138 itp->waiting = ClampTo<uint16_t>(itp->waiting + ScaleByCargoScale(45, false));
1139 break;
1140 }
1141}
1142
1148static void ProduceIndustryGoodsHelper(Industry *i, bool scale)
1149{
1150 for (auto &p : i->produced) {
1151 if (!IsValidCargoType(p.cargo)) continue;
1152
1153 uint16_t amount = p.rate;
1154 if (scale) amount = ScaleByCargoScale(amount, false);
1155
1156 p.waiting = ClampTo<uint16_t>(p.waiting + amount);
1157 }
1158}
1159
1160static void ProduceIndustryGoods(Industry *i)
1161{
1162 const IndustrySpec *indsp = GetIndustrySpec(i->type);
1163
1164 /* play a sound? */
1165 if ((i->counter & 0x3F) == 0) {
1166 uint32_t r;
1167 if (Chance16R(1, 14, r) && !indsp->random_sounds.empty() && _settings_client.sound.ambient) {
1168 if (std::any_of(std::begin(i->produced), std::end(i->produced), [](const auto &p) { return p.history[LAST_MONTH].production > 0; })) {
1169 /* Play sound since last month had production */
1170 SndPlayTileFx(
1171 static_cast<SoundFx>(indsp->random_sounds[((r >> 16) * indsp->random_sounds.size()) >> 16]),
1172 i->location.tile);
1173 }
1174 }
1175 }
1176
1177 i->counter--;
1178
1179 /* If using an industry callback, scale the callback interval by cargo scale percentage. */
1184 }
1185 }
1186
1187 /*
1188 * All other production and special effects happen every 256 ticks, and cargo production is just scaled by the cargo scale percentage.
1189 * 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.
1190 */
1191 if ((i->counter % Ticks::INDUSTRY_PRODUCE_TICKS) == 0) {
1192 /* Handle non-callback cargo production. */
1194
1195 IndustryBehaviours indbehav = indsp->behaviour;
1196
1197 if (indbehav.Test(IndustryBehaviour::PlantFields)) {
1198 uint16_t cb_res = CALLBACK_FAILED;
1200 cb_res = GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 0, i, i->type, i->location.tile);
1201 }
1202
1203 bool plant;
1204 if (cb_res != CALLBACK_FAILED) {
1206 } else {
1207 plant = Chance16(1, 8);
1208 }
1209
1210 if (plant) PlantRandomFarmField(i);
1211 }
1212 if (indbehav.Test(IndustryBehaviour::CutTrees)) {
1213 uint16_t cb_res = CALLBACK_FAILED;
1215 cb_res = GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 1, i, i->type, i->location.tile);
1216 }
1217
1218 bool cut;
1219 if (cb_res != CALLBACK_FAILED) {
1221 } else {
1222 cut = ((i->counter % Ticks::INDUSTRY_CUT_TREE_TICKS) == 0);
1223 }
1224
1225 if (cut) ChopLumberMillTrees(i);
1226 }
1227
1229 TriggerIndustryAnimation(i, IndustryAnimationTrigger::IndustryTick);
1230 }
1231}
1232
1233void OnTick_Industry()
1234{
1235 if (_industry_sound_ctr != 0) {
1236 _industry_sound_ctr++;
1237
1238 if (_industry_sound_ctr == 75) {
1239 if (_settings_client.sound.ambient) SndPlayTileFx(SND_37_LUMBER_MILL_2, _industry_sound_tile);
1240 } else if (_industry_sound_ctr == 160) {
1241 _industry_sound_ctr = 0;
1242 if (_settings_client.sound.ambient) SndPlayTileFx(SND_36_LUMBER_MILL_3, _industry_sound_tile);
1243 }
1244 }
1245
1246 if (_game_mode == GM_EDITOR) return;
1247
1248 for (Industry *i : Industry::Iterate()) {
1249 ProduceIndustryGoods(i);
1250
1251 if ((TimerGameTick::counter + i->index) % Ticks::DAY_TICKS == 0) {
1252 for (auto &a : i->accepted) a.accumulated_waiting += a.waiting;
1253 }
1254 }
1255}
1256
1262{
1263 return CommandCost();
1264}
1265
1272{
1273 if (_settings_game.game_creation.landscape == LandscapeType::Arctic) {
1274 if (GetTileZ(tile) < HighestSnowLine() + 2) {
1275 return CommandCost(STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED);
1276 }
1277 }
1278 return CommandCost();
1279}
1280
1288static bool CheckScaledDistanceFromEdge(TileIndex tile, uint maxdist)
1289{
1290 uint maxdist_x = maxdist;
1291 uint maxdist_y = maxdist;
1292
1293 if (Map::SizeX() > 256) maxdist_x *= Map::SizeX() / 256;
1294 if (Map::SizeY() > 256) maxdist_y *= Map::SizeY() / 256;
1295
1296 if (DistanceFromEdgeDir(tile, DIAGDIR_NE) < maxdist_x) return true;
1297 if (DistanceFromEdgeDir(tile, DIAGDIR_NW) < maxdist_y) return true;
1298 if (DistanceFromEdgeDir(tile, DIAGDIR_SW) < maxdist_x) return true;
1299 if (DistanceFromEdgeDir(tile, DIAGDIR_SE) < maxdist_y) return true;
1300
1301 return false;
1302}
1303
1310{
1311 if (_game_mode == GM_EDITOR) return CommandCost();
1312
1313 if (CheckScaledDistanceFromEdge(TileAddXY(tile, 1, 1), _settings_game.game_creation.oil_refinery_limit)) return CommandCost();
1314
1315 return CommandCost(STR_ERROR_CAN_ONLY_BE_POSITIONED);
1316}
1317
1318extern bool _ignore_industry_restrictions;
1319
1326{
1327 if (_game_mode == GM_EDITOR && _ignore_industry_restrictions) return CommandCost();
1328
1329 if (TileHeight(tile) == 0 &&
1330 CheckScaledDistanceFromEdge(TileAddXY(tile, 1, 1), _settings_game.game_creation.oil_refinery_limit)) return CommandCost();
1331
1332 return CommandCost(STR_ERROR_CAN_ONLY_BE_POSITIONED);
1333}
1334
1341{
1342 if (_settings_game.game_creation.landscape == LandscapeType::Arctic) {
1343 if (GetTileZ(tile) + 2 >= HighestSnowLine()) {
1344 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1345 }
1346 }
1347 return CommandCost();
1348}
1349
1356{
1357 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
1358 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1359 }
1360 return CommandCost();
1361}
1362
1369{
1370 if (GetTropicZone(tile) != TROPICZONE_DESERT) {
1371 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT);
1372 }
1373 return CommandCost();
1374}
1375
1382{
1383 if (GetTropicZone(tile) != TROPICZONE_RAINFOREST) {
1384 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST);
1385 }
1386 return CommandCost();
1387}
1388
1395{
1396 if (GetTileZ(tile) > 4) {
1397 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS);
1398 }
1399 return CommandCost();
1400}
1401
1408
1421
1432static CommandCost FindTownForIndustry(TileIndex tile, IndustryType type, Town **t)
1433{
1434 *t = ClosestTownFromTile(tile, UINT_MAX);
1435
1436 if (_settings_game.economy.multiple_industry_per_town) return CommandCost();
1437
1438 for (const IndustryID &industry : Industry::industries[type]) {
1439 if (Industry::Get(industry)->town == *t) {
1440 *t = nullptr;
1441 return CommandCost(STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN);
1442 }
1443 }
1444
1445 return CommandCost();
1446}
1447
1448bool IsSlopeRefused(Slope current, Slope refused)
1449{
1450 if (IsSteepSlope(current)) return true;
1451 if (current != SLOPE_FLAT) {
1452 if (IsSteepSlope(refused)) return true;
1453
1454 Slope t = ComplementSlope(current);
1455
1456 if ((refused & SLOPE_W) && (t & SLOPE_NW)) return true;
1457 if ((refused & SLOPE_S) && (t & SLOPE_NE)) return true;
1458 if ((refused & SLOPE_E) && (t & SLOPE_SW)) return true;
1459 if ((refused & SLOPE_N) && (t & SLOPE_SE)) return true;
1460 }
1461
1462 return false;
1463}
1464
1472static CommandCost CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTileLayout &layout, IndustryType type)
1473{
1474 IndustryBehaviours ind_behav = GetIndustrySpec(type)->behaviour;
1475
1476 for (const IndustryTileLayoutTile &it : layout) {
1477 IndustryGfx gfx = GetTranslatedIndustryTileID(it.gfx);
1478 TileIndex cur_tile = TileAddWrap(tile, it.ti.x, it.ti.y);
1479
1480 if (!IsValidTile(cur_tile)) {
1481 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1482 }
1483
1484 if (gfx == GFX_WATERTILE_SPECIALCHECK) {
1485 if (!IsWaterTile(cur_tile) ||
1486 !IsTileFlat(cur_tile)) {
1487 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1488 }
1489 } else {
1490 CommandCost ret = EnsureNoVehicleOnGround(cur_tile);
1491 if (ret.Failed()) return ret;
1492 if (IsBridgeAbove(cur_tile)) return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1493
1494 const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
1495
1496 /* Perform land/water check if not disabled */
1497 if (!HasBit(its->slopes_refused, 5) && ((HasTileWaterClass(cur_tile) && IsTileOnWater(cur_tile)) != ind_behav.Test(IndustryBehaviour::BuiltOnWater))) return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1498
1499 if (ind_behav.Any({IndustryBehaviour::OnlyInTown, IndustryBehaviour::Town1200More}) || // Tile must be a house
1500 (ind_behav.Test(IndustryBehaviour::OnlyNearTown) && IsTileType(cur_tile, TileType::House))) { // Tile is allowed to be a house (and it is a house)
1501 if (!IsTileType(cur_tile, TileType::House)) {
1502 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS);
1503 }
1504
1505 /* Clear the tiles as OWNER_TOWN to not affect town rating, and to not clear protected buildings */
1507 ret = Command<Commands::LandscapeClear>::Do({}, cur_tile);
1508 cur_company.Restore();
1509
1510 if (ret.Failed()) return ret;
1511 } else {
1512 /* Clear the tiles, but do not affect town ratings */
1513 ret = Command<Commands::LandscapeClear>::Do({DoCommandFlag::Auto, DoCommandFlag::NoTestTownRating, DoCommandFlag::NoModifyTownRating}, cur_tile);
1514 if (ret.Failed()) return ret;
1515 }
1516 }
1517 }
1518
1519 return CommandCost();
1520}
1521
1534static 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)
1535{
1536 bool refused_slope = false;
1537 bool custom_shape = false;
1538
1539 for (const IndustryTileLayoutTile &it : layout) {
1540 IndustryGfx gfx = GetTranslatedIndustryTileID(it.gfx);
1541 TileIndex cur_tile = TileAddWrap(tile, it.ti.x, it.ti.y);
1542 assert(IsValidTile(cur_tile)); // checked before in CheckIfIndustryTilesAreFree
1543
1544 if (gfx != GFX_WATERTILE_SPECIALCHECK) {
1545 const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
1546
1548 custom_shape = true;
1549 CommandCost ret = PerformIndustryTileSlopeCheck(tile, cur_tile, its, type, gfx, layout_index, initial_random_bits, founder, creation_type);
1550 if (ret.Failed()) return ret;
1551 } else {
1552 Slope tileh = GetTileSlope(cur_tile);
1553 refused_slope |= IsSlopeRefused(tileh, its->slopes_refused);
1554 }
1555 }
1556 }
1557
1558 if (custom_shape_check != nullptr) *custom_shape_check = custom_shape;
1559
1560 /* It is almost impossible to have a fully flat land in TG, so what we
1561 * do is that we check if we can make the land flat later on. See
1562 * CheckIfCanLevelIndustryPlatform(). */
1563 if (!refused_slope || (_settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world && !custom_shape && !_ignore_industry_restrictions)) {
1564 return CommandCost();
1565 }
1566 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1567}
1568
1576static CommandCost CheckIfIndustryIsAllowed(TileIndex tile, IndustryType type, const Town *t)
1577{
1578 if (GetIndustrySpec(type)->behaviour.Test(IndustryBehaviour::Town1200More) && t->cache.population < 1200) {
1579 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200);
1580 }
1581
1582 if (GetIndustrySpec(type)->behaviour.Test(IndustryBehaviour::OnlyNearTown) && DistanceMax(t->xy, tile) > 9) {
1583 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER);
1584 }
1585
1586 return CommandCost();
1587}
1588
1589static bool CheckCanTerraformSurroundingTiles(TileIndex tile, uint height, int internal)
1590{
1591 /* Check if we don't leave the map */
1592 if (TileX(tile) == 0 || TileY(tile) == 0 || GetTileType(tile) == TileType::Void) return false;
1593
1594 TileArea ta(tile - TileDiffXY(1, 1), 2, 2);
1595 for (TileIndex tile_walk : ta) {
1596 uint curh = TileHeight(tile_walk);
1597 /* Is the tile clear? */
1598 if ((GetTileType(tile_walk) != TileType::Clear) && (GetTileType(tile_walk) != TileType::Trees)) return false;
1599
1600 /* Don't allow too big of a change if this is the sub-tile check */
1601 if (internal != 0 && Delta(curh, height) > 1) return false;
1602
1603 /* Different height, so the surrounding tiles of this tile
1604 * has to be correct too (in level, or almost in level)
1605 * else you get a chain-reaction of terraforming. */
1606 if (internal == 0 && curh != height) {
1607 if (TileX(tile_walk) == 0 || TileY(tile_walk) == 0 || !CheckCanTerraformSurroundingTiles(tile_walk + TileDiffXY(-1, -1), height, internal + 1)) {
1608 return false;
1609 }
1610 }
1611 }
1612
1613 return true;
1614}
1615
1624static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, DoCommandFlags flags, const IndustryTileLayout &layout)
1625{
1626 int max_x = 0;
1627 int max_y = 0;
1628
1629 /* Finds dimensions of largest variant of this industry */
1630 for (const IndustryTileLayoutTile &it : layout) {
1631 if (it.gfx == GFX_WATERTILE_SPECIALCHECK) continue; // watercheck tiles don't count for footprint size
1632 if (it.ti.x > max_x) max_x = it.ti.x;
1633 if (it.ti.y > max_y) max_y = it.ti.y;
1634 }
1635
1636 /* Remember level height */
1637 uint h = TileHeight(tile);
1638
1639 if (TileX(tile) <= _settings_game.construction.industry_platform + 1U || TileY(tile) <= _settings_game.construction.industry_platform + 1U) return false;
1640 /* Check that all tiles in area and surrounding are clear
1641 * this determines that there are no obstructing items */
1642
1643 /* TileArea::Expand is not used here as we need to abort
1644 * instead of clamping if the bounds cannot expanded. */
1645 TileArea ta(tile + TileDiffXY(-_settings_game.construction.industry_platform, -_settings_game.construction.industry_platform),
1646 max_x + 2 + 2 * _settings_game.construction.industry_platform, max_y + 2 + 2 * _settings_game.construction.industry_platform);
1647
1648 if (TileX(ta.tile) + ta.w >= Map::MaxX() || TileY(ta.tile) + ta.h >= Map::MaxY()) return false;
1649
1650 /* _current_company is OWNER_NONE for randomly generated industries and in editor, or the company who funded or prospected the industry.
1651 * Perform terraforming as OWNER_TOWN to disable autoslope and town ratings. */
1653
1654 for (TileIndex tile_walk : ta) {
1655 uint curh = TileHeight(tile_walk);
1656 if (curh != h) {
1657 /* This tile needs terraforming. Check if we can do that without
1658 * damaging the surroundings too much. */
1659 if (!CheckCanTerraformSurroundingTiles(tile_walk, h, 0)) {
1660 cur_company.Restore();
1661 return false;
1662 }
1663 /* This is not 100% correct check, but the best we can do without modifying the map.
1664 * What is missing, is if the difference in height is more than 1.. */
1665 if (std::get<0>(Command<Commands::TerraformLand>::Do(DoCommandFlags{flags}.Reset(DoCommandFlag::Execute), tile_walk, SLOPE_N, curh <= h)).Failed()) {
1666 cur_company.Restore();
1667 return false;
1668 }
1669 }
1670 }
1671
1672 if (flags.Test(DoCommandFlag::Execute)) {
1673 /* Terraform the land under the industry */
1674 for (TileIndex tile_walk : ta) {
1675 uint curh = TileHeight(tile_walk);
1676 while (curh != h) {
1677 /* We give the terraforming for free here, because we can't calculate
1678 * exact cost in the test-round, and as we all know, that will cause
1679 * a nice assert if they don't match ;) */
1680 Command<Commands::TerraformLand>::Do(flags, tile_walk, SLOPE_N, curh <= h);
1681 curh += (curh > h) ? -1 : 1;
1682 }
1683 }
1684 }
1685
1686 cur_company.Restore();
1687 return true;
1688}
1689
1690
1698{
1699 const IndustrySpec *indspec = GetIndustrySpec(type);
1700
1701 for (IndustryType conflicting_type : indspec->conflicting) {
1702 if (conflicting_type == IT_INVALID) continue;
1703
1704 for (const IndustryID &industry : Industry::industries[conflicting_type]) {
1705 /* Within 14 tiles from another industry is considered close */
1706 if (DistanceMax(tile, Industry::Get(industry)->location.tile) > 14) continue;
1707
1708 return CommandCost(STR_ERROR_INDUSTRY_TOO_CLOSE);
1709 }
1710 }
1711 return CommandCost();
1712}
1713
1718static void AdvertiseIndustryOpening(const Industry *ind)
1719{
1720 const IndustrySpec *ind_spc = GetIndustrySpec(ind->type);
1721 EncodedString headline;
1722 if (ind_spc->new_industry_text > STR_LAST_STRINGID) {
1723 headline = GetEncodedString(ind_spc->new_industry_text, ind_spc->name, STR_TOWN_NAME, ind->town->index);
1724 } else {
1725 headline = GetEncodedString(ind_spc->new_industry_text, ind_spc->name, ind->town->index);
1726 }
1727 AddIndustryNewsItem(std::move(headline), NewsType::IndustryOpen, ind->index);
1728 AI::BroadcastNewEvent(new ScriptEventIndustryOpen(ind->index));
1729 Game::NewEvent(new ScriptEventIndustryOpen(ind->index));
1730}
1731
1738{
1739 if (ind->neutral_station != nullptr && !_settings_game.station.serve_neutral_industries) {
1740 /* Industry has a neutral station. Use it and ignore any other nearby stations. */
1741 ind->stations_near.insert(ind->neutral_station);
1742 ind->neutral_station->industries_near.clear();
1744 return;
1745 }
1746
1747 ForAllStationsAroundTiles(ind->location, [ind](Station *st, TileIndex tile) {
1748 if (!IsTileType(tile, TileType::Industry) || GetIndustryIndex(tile) != ind->index) return false;
1749 ind->stations_near.insert(st);
1750 st->AddIndustryToDeliver(ind, tile);
1751 return false;
1752 });
1753}
1754
1766static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, const IndustryTileLayout &layout, size_t layout_index, Town *t, Owner founder, uint16_t initial_random_bits)
1767{
1768 const IndustrySpec *indspec = GetIndustrySpec(type);
1769
1770 i->location = TileArea(tile, 1, 1);
1771 i->type = type;
1772
1773 auto &industries = Industry::industries[type];
1774 industries.insert(i->index);
1775
1776 size_t produced_count = 0;
1777 for (size_t index = 0; index < std::size(indspec->produced_cargo); ++index) {
1778 if (IsValidCargoType(indspec->produced_cargo[index])) {
1779 produced_count = index + 1;
1780 }
1781 }
1782 for (size_t index = 0; index < produced_count; ++index) {
1783 Industry::ProducedCargo &p = i->produced.emplace_back();
1784 p.cargo = indspec->produced_cargo[index];
1785 p.rate = indspec->production_rate[index];
1786 }
1787
1788 size_t accepted_count = 0;
1789 for (size_t index = 0; index < std::size(indspec->accepts_cargo); ++index) {
1790 if (IsValidCargoType(indspec->accepts_cargo[index])) {
1791 accepted_count = index + 1;
1792 }
1793 }
1794 for (size_t index = 0; index < accepted_count; ++index) {
1795 Industry::AcceptedCargo &a = i->accepted.emplace_back();
1796 a.cargo = indspec->accepts_cargo[index];
1797 }
1798
1799 /* Randomize initial production if non-original economy is used and there are no production related callbacks. */
1800 if (!indspec->UsesOriginalEconomy()) {
1801 for (auto &p : i->produced) {
1802 p.rate = ClampTo<uint8_t>((RandomRange(256) + 128) * p.rate >> 8);
1803 }
1804 }
1805
1806 i->town = t;
1807 i->owner = OWNER_NONE;
1808
1809 uint16_t r = Random();
1810 i->random_colour = static_cast<Colours>(GB(r, 0, 4));
1811 i->counter = GB(r, 4, 12);
1812 i->random = initial_random_bits;
1813 i->was_cargo_delivered = false;
1815 i->founder = founder;
1816 i->ctlflags = {};
1817
1819 i->construction_type = (_game_mode == GM_EDITOR) ? ICT_SCENARIO_EDITOR :
1821
1822 /* Adding 1 here makes it conform to specs of var44 of varaction2 for industries
1823 * 0 = created prior of newindustries
1824 * else, chosen layout + 1 */
1825 i->selected_layout = (uint8_t)(layout_index + 1);
1826
1829
1831
1832 /* Call callbacks after the regular fields got initialised. */
1833
1835 uint16_t res = GetIndustryCallback(CBID_INDUSTRY_PROD_CHANGE_BUILD, 0, Random(), i, type, INVALID_TILE);
1836 if (res != CALLBACK_FAILED) {
1837 if (res < PRODLEVEL_MINIMUM || res > PRODLEVEL_MAXIMUM) {
1839 } else {
1840 i->prod_level = res;
1842 }
1843 }
1844 }
1845
1846 if (_generating_world) {
1849 for (auto &p : i->produced) {
1850 if (IsValidCargoType(p.cargo)) p.history[LAST_MONTH].production = ScaleByCargoScale(p.waiting * 8, false);
1851 p.waiting = 0;
1852 }
1853 }
1854
1855 for (auto &p : i->produced) {
1856 if (IsValidCargoType(p.cargo)) p.history[LAST_MONTH].production += ScaleByCargoScale(p.rate * 8, false);
1857 }
1858
1860 }
1861
1863 uint16_t res = GetIndustryCallback(CBID_INDUSTRY_DECIDE_COLOUR, 0, 0, i, type, INVALID_TILE);
1864 if (res != CALLBACK_FAILED) {
1865 if (GB(res, 4, 11) != 0) ErrorUnknownCallbackResult(indspec->grf_prop.grfid, CBID_INDUSTRY_DECIDE_COLOUR, res);
1866 i->random_colour = static_cast<Colours>(GB(res, 0, 4));
1867 }
1868 }
1869
1871 /* Clear all input cargo types */
1872 i->accepted.clear();
1873 /* Query actual types */
1875 for (uint j = 0; j < maxcargoes; j++) {
1877 if (res == CALLBACK_FAILED || GB(res, 0, 8) == UINT8_MAX) break;
1878 if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
1880 break;
1881 }
1882 CargoType cargo = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
1883 /* Industries without "unlimited" cargo types support depend on the specific order/slots of cargo types.
1884 * They need to be able to blank out specific slots without aborting the callback sequence,
1885 * and solve this by returning undefined cargo indexes. Skip these. */
1887 /* As slots are allocated as needed now, this means we do need to add a slot for the invalid cargo. */
1888 Industry::AcceptedCargo &a = i->accepted.emplace_back();
1889 a.cargo = INVALID_CARGO;
1890 continue;
1891 }
1892 /* Verify valid cargo */
1893 if (std::ranges::find(indspec->accepts_cargo, cargo) == std::end(indspec->accepts_cargo)) {
1894 /* Cargo not in spec, error in NewGRF */
1896 break;
1897 }
1898 if (std::any_of(std::begin(i->accepted), std::begin(i->accepted) + j, [&cargo](const auto &a) { return a.cargo == cargo; })) {
1899 /* Duplicate cargo */
1901 break;
1902 }
1903 Industry::AcceptedCargo &a = i->accepted.emplace_back();
1904 a.cargo = cargo;
1905 }
1906 }
1907
1909 /* Clear all output cargo types */
1910 i->produced.clear();
1911 /* Query actual types */
1913 for (uint j = 0; j < maxcargoes; j++) {
1915 if (res == CALLBACK_FAILED || GB(res, 0, 8) == UINT8_MAX) break;
1916 if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
1918 break;
1919 }
1920 CargoType cargo = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
1921 /* Allow older GRFs to skip slots. */
1923 /* As slots are allocated as needed now, this means we do need to add a slot for the invalid cargo. */
1924 Industry::ProducedCargo &p = i->produced.emplace_back();
1925 p.cargo = INVALID_CARGO;
1926 continue;
1927 }
1928 /* Verify valid cargo */
1929 if (std::ranges::find(indspec->produced_cargo, cargo) == std::end(indspec->produced_cargo)) {
1930 /* Cargo not in spec, error in NewGRF */
1932 break;
1933 }
1934 if (std::any_of(std::begin(i->produced), std::begin(i->produced) + j, [&cargo](const auto &p) { return p.cargo == cargo; })) {
1935 /* Duplicate cargo */
1937 break;
1938 }
1939 Industry::ProducedCargo &p = i->produced.emplace_back();
1940 p.cargo = cargo;
1941 }
1942 }
1943
1944 /* Plant the tiles */
1945
1946 for (const IndustryTileLayoutTile &it : layout) {
1947 TileIndex cur_tile = tile + ToTileIndexDiff(it.ti);
1948
1949 if (it.gfx != GFX_WATERTILE_SPECIALCHECK) {
1950 i->location.Add(cur_tile);
1951
1952 WaterClass wc = (IsWaterTile(cur_tile) ? GetWaterClass(cur_tile) : WaterClass::Invalid);
1953
1954 Command<Commands::LandscapeClear>::Do({DoCommandFlag::Execute, DoCommandFlag::NoTestTownRating, DoCommandFlag::NoModifyTownRating}, cur_tile);
1955
1956 MakeIndustry(cur_tile, i->index, it.gfx, Random(), wc);
1957
1958 if (_generating_world) {
1959 SetIndustryConstructionCounter(cur_tile, 3);
1960 SetIndustryConstructionStage(cur_tile, 2);
1961 }
1962
1963 /* it->gfx is stored in the map. But the translated ID cur_gfx is the interesting one */
1964 IndustryGfx cur_gfx = GetTranslatedIndustryTileID(it.gfx);
1965 const IndustryTileSpec *its = GetIndustryTileSpec(cur_gfx);
1966 if (its->animation.status != AnimationStatus::NoAnimation) AddAnimatedTile(cur_tile);
1967 }
1968 }
1969
1970 /* Call callbacks after all tiles have been created. */
1971 for (TileIndex cur_tile : i->location) {
1972 if (i->TileBelongsToIndustry(cur_tile)) {
1973 /* There are no shared random bits, consistent with "MakeIndustryTileBigger" in tile loop.
1974 * So, trigger tiles individually */
1975 TriggerIndustryTileAnimation_ConstructionStageChanged(cur_tile, true);
1976 }
1977 }
1978
1980 for (uint j = 0; j != 50; j++) PlantRandomFarmField(i);
1981 }
1982 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, IDIWD_FORCE_REBUILD);
1984
1986}
1987
2004static 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)
2005{
2006 assert(layout_index < indspec->layouts.size());
2007 const IndustryTileLayout &layout = indspec->layouts[layout_index];
2008
2009 *ip = nullptr;
2010
2011 /* 1. Cheap: Built-in checks on industry level. */
2013 if (ret.Failed()) return ret;
2014
2015 Town *t = nullptr;
2016 ret = FindTownForIndustry(tile, type, &t);
2017 if (ret.Failed()) return ret;
2018 assert(t != nullptr);
2019
2020 ret = CheckIfIndustryIsAllowed(tile, type, t);
2021 if (ret.Failed()) return ret;
2022
2023 /* 2. Built-in checks on industry tiles. */
2024 std::vector<ClearedObjectArea> object_areas(_cleared_object_areas);
2025 ret = CheckIfIndustryTilesAreFree(tile, layout, type);
2026 _cleared_object_areas = std::move(object_areas);
2027 if (ret.Failed()) return ret;
2028
2029 /* 3. NewGRF-defined checks on industry level. */
2030 if (GetIndustrySpec(type)->callback_mask.Test(IndustryCallbackMask::Location)) {
2031 ret = CheckIfCallBackAllowsCreation(tile, type, layout_index, random_var8f, random_initial_bits, founder, creation_type);
2032 } else {
2033 ret = _check_new_industry_procs[indspec->check_proc](tile);
2034 }
2035 if (ret.Failed()) return ret;
2036
2037 /* 4. Expensive: NewGRF-defined checks on industry tiles. */
2038 bool custom_shape_check = false;
2039 ret = CheckIfIndustryTileSlopes(tile, layout, layout_index, type, random_initial_bits, founder, creation_type, &custom_shape_check);
2040 if (ret.Failed()) return ret;
2041
2042 if (!custom_shape_check && _settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world &&
2043 !_ignore_industry_restrictions && !CheckIfCanLevelIndustryPlatform(tile, DoCommandFlag::NoWater, layout)) {
2044 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
2045 }
2046
2047 if (!Industry::CanAllocateItem()) return CommandCost(STR_ERROR_TOO_MANY_INDUSTRIES);
2048
2049 if (flags.Test(DoCommandFlag::Execute)) {
2050 *ip = Industry::Create(tile);
2051 if (!custom_shape_check) CheckIfCanLevelIndustryPlatform(tile, {DoCommandFlag::NoWater, DoCommandFlag::Execute}, layout);
2052 DoCreateNewIndustry(*ip, tile, type, layout, layout_index, t, founder, random_initial_bits);
2053 }
2054
2055 return CommandCost();
2056}
2057
2068CommandCost CmdBuildIndustry(DoCommandFlags flags, TileIndex tile, IndustryType it, uint32_t first_layout, bool fund, uint32_t seed)
2069{
2070 if (it >= NUM_INDUSTRYTYPES) return CMD_ERROR;
2071
2072 const IndustrySpec *indspec = GetIndustrySpec(it);
2073
2074 /* Check if the to-be built/founded industry is available for this climate. */
2075 if (!indspec->enabled || indspec->layouts.empty()) return CMD_ERROR;
2076
2077 /* If the setting for raw-material industries is not on, you cannot build raw-material industries.
2078 * Raw material industries are industries that do not accept cargo (at least for now) */
2079 if (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 0 && indspec->IsRawIndustry()) {
2080 return CMD_ERROR;
2081 }
2082
2083 if (_game_mode != GM_EDITOR && GetIndustryProbabilityCallback(it, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, 1) == 0) {
2084 return CMD_ERROR;
2085 }
2086
2087 Randomizer randomizer;
2088 randomizer.SetSeed(seed);
2089 uint16_t random_initial_bits = GB(seed, 0, 16);
2090 uint32_t random_var8f = randomizer.Next();
2091 size_t num_layouts = indspec->layouts.size();
2092 CommandCost ret = CommandCost(STR_ERROR_SITE_UNSUITABLE);
2093 const bool deity_prospect = _current_company == OWNER_DEITY && !fund;
2094
2095 Industry *ind = nullptr;
2096 if (deity_prospect || (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 2 && indspec->IsRawIndustry())) {
2097 if (flags.Test(DoCommandFlag::Execute)) {
2098 /* Prospecting has a chance to fail, however we cannot guarantee that something can
2099 * be built on the map, so the chance gets lower when the map is fuller, but there
2100 * is nothing we can really do about that. */
2101 bool prospect_success = deity_prospect || Random() <= indspec->prospecting_chance;
2102 if (prospect_success) {
2103 /* Prospected industries are build as OWNER_TOWN to not e.g. be build on owned land of the founder */
2106 for (int i = 0; i < 5000; i++) {
2107 /* We should not have more than one Random() in a function call
2108 * because parameter evaluation order is not guaranteed in the c++ standard
2109 */
2110 tile = RandomTile();
2111 /* Start with a random layout */
2112 size_t layout = RandomRange((uint32_t)num_layouts);
2113 /* Check now each layout, starting with the random one */
2114 for (size_t j = 0; j < num_layouts; j++) {
2115 layout = (layout + 1) % num_layouts;
2116 ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, cur_company.GetOriginalValue(), calltype, &ind);
2117 if (ret.Succeeded()) break;
2118 }
2119 if (ret.Succeeded()) break;
2120 }
2121 cur_company.Restore();
2122 }
2123 if (ret.Failed() && IsLocalCompany()) {
2124 if (prospect_success) {
2125 ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_PROSPECT_INDUSTRY), GetEncodedString(STR_ERROR_NO_SUITABLE_PLACES_FOR_PROSPECTING), WL_INFO);
2126 } else {
2127 ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_PROSPECT_INDUSTRY), GetEncodedString(STR_ERROR_PROSPECTING_WAS_UNLUCKY), WL_INFO);
2128 }
2129 }
2130 }
2131 } else {
2132 size_t layout = first_layout;
2133 if (layout >= num_layouts) return CMD_ERROR;
2134
2135 /* Check subsequently each layout, starting with the given layout in p1 */
2136 for (size_t i = 0; i < num_layouts; i++) {
2137 layout = (layout + 1) % num_layouts;
2138 ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, _current_company, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, &ind);
2139 if (ret.Succeeded()) break;
2140 }
2141
2142 /* If it still failed, there's no suitable layout to build here, return the error */
2143 if (ret.Failed()) return ret;
2144 }
2145
2146 if (flags.Test(DoCommandFlag::Execute) && ind != nullptr && _game_mode != GM_EDITOR) {
2148 }
2149
2151}
2152
2160CommandCost CmdIndustrySetFlags(DoCommandFlags flags, IndustryID ind_id, IndustryControlFlags ctlflags)
2161{
2162 if (_current_company != OWNER_DEITY) return CMD_ERROR;
2163
2164 Industry *ind = Industry::GetIfValid(ind_id);
2165 if (ind == nullptr) return CMD_ERROR;
2166 if (!ctlflags.IsValid()) return CMD_ERROR;
2167
2168 if (flags.Test(DoCommandFlag::Execute)) ind->ctlflags = ctlflags;
2169
2170 return CommandCost();
2171}
2172
2182CommandCost CmdIndustrySetProduction(DoCommandFlags flags, IndustryID ind_id, uint8_t prod_level, bool show_news, const EncodedString &custom_news)
2183{
2184 if (_current_company != OWNER_DEITY) return CMD_ERROR;
2185 if (prod_level < PRODLEVEL_MINIMUM || prod_level > PRODLEVEL_MAXIMUM) return CMD_ERROR;
2186
2187 Industry *ind = Industry::GetIfValid(ind_id);
2188 if (ind == nullptr) return CMD_ERROR;
2189
2190 if (flags.Test(DoCommandFlag::Execute)) {
2192 ind->prod_level = prod_level;
2194
2195 /* Show news message if requested. */
2196 if (show_news && prod_level != ind->prod_level) {
2197 NewsType nt;
2198 switch (WhoCanServiceIndustry(ind)) {
2199 case 0: nt = NewsType::IndustryNobody; break;
2200 case 1: nt = NewsType::IndustryOther; break;
2201 case 2: nt = NewsType::IndustryCompany; break;
2202 default: NOT_REACHED();
2203 }
2204
2205 /* Set parameters of news string */
2206 EncodedString headline;
2207 if (!custom_news.empty()) {
2208 headline = custom_news;
2209 } else {
2210 StringID str = (prod_level > ind->prod_level)
2213
2214 if (str > STR_LAST_STRINGID) {
2215 headline = GetEncodedString(str, STR_TOWN_NAME, ind->town->index, GetIndustrySpec(ind->type)->name);
2216 } else {
2217 headline = GetEncodedString(str, ind->index);
2218 }
2219 }
2220
2221 AddIndustryNewsItem(std::move(headline), nt, ind->index);
2222 }
2223 }
2224
2225 return CommandCost();
2226}
2227
2237CommandCost CmdIndustrySetExclusivity(DoCommandFlags flags, IndustryID ind_id, Owner company_id, bool consumer)
2238{
2239 if (_current_company != OWNER_DEITY) return CMD_ERROR;
2240
2241 Industry *ind = Industry::GetIfValid(ind_id);
2242 if (ind == nullptr) return CMD_ERROR;
2243
2244 if (company_id != OWNER_NONE && company_id != INVALID_OWNER && company_id != OWNER_DEITY
2245 && !Company::IsValidID(company_id)) return CMD_ERROR;
2246
2247 if (flags.Test(DoCommandFlag::Execute)) {
2248 if (consumer) {
2249 ind->exclusive_consumer = company_id;
2250 } else {
2251 ind->exclusive_supplier = company_id;
2252 }
2253 }
2254
2255
2256 return CommandCost();
2257}
2258
2266CommandCost CmdIndustrySetText(DoCommandFlags flags, IndustryID ind_id, const EncodedString &text)
2267{
2268 if (_current_company != OWNER_DEITY) return CMD_ERROR;
2269
2270 Industry *ind = Industry::GetIfValid(ind_id);
2271 if (ind == nullptr) return CMD_ERROR;
2272
2273 if (flags.Test(DoCommandFlag::Execute)) {
2274 ind->text.clear();
2275 if (!text.empty()) ind->text = text;
2277 }
2278
2279 return CommandCost();
2280}
2281
2289static Industry *CreateNewIndustry(TileIndex tile, IndustryType type, IndustryAvailabilityCallType creation_type)
2290{
2291 const IndustrySpec *indspec = GetIndustrySpec(type);
2292
2293 uint32_t seed = Random();
2294 uint32_t seed2 = Random();
2295 Industry *i = nullptr;
2296 size_t layout_index = RandomRange((uint32_t)indspec->layouts.size());
2297 [[maybe_unused]] CommandCost ret = CreateNewIndustryHelper(tile, type, DoCommandFlag::Execute, indspec, layout_index, seed, GB(seed2, 0, 16), OWNER_NONE, creation_type, &i);
2298 assert(i != nullptr || ret.Failed());
2299 return i;
2300}
2301
2309static uint32_t GetScaledIndustryGenerationProbability(IndustryType it, std::optional<bool> water, bool *force_at_least_one)
2310{
2311 const IndustrySpec *ind_spc = GetIndustrySpec(it);
2312 if (water.has_value() && ind_spc->behaviour.Test(IndustryBehaviour::BuiltOnWater) != *water) return 0;
2313
2314 uint32_t chance = ind_spc->appear_creation[to_underlying(_settings_game.game_creation.landscape)];
2315 if (!ind_spc->enabled || ind_spc->layouts.empty() ||
2316 (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == IndustryDensity::FundedOnly) ||
2317 (chance = GetIndustryProbabilityCallback(it, IACT_MAPGENERATION, chance)) == 0) {
2318 *force_at_least_one = false;
2319 return 0;
2320 } else {
2321 chance *= 16; // to increase precision
2322 /* We want industries appearing at coast to appear less often on bigger maps, as length of coast increases slower than map area.
2323 * For simplicity we scale in both cases, though scaling the probabilities of all industries has no effect. */
2324 chance = (ind_spc->check_proc == CHECK_REFINERY || ind_spc->check_proc == CHECK_OIL_RIG) ? Map::ScaleBySize1D(chance) : Map::ScaleBySize(chance);
2325
2326 *force_at_least_one = (chance > 0) && !ind_spc->behaviour.Test(IndustryBehaviour::NoBuildMapCreation) && (_game_mode != GM_EDITOR);
2327 return chance;
2328 }
2329}
2330
2337static uint16_t GetIndustryGamePlayProbability(IndustryType it, uint8_t *min_number)
2338{
2339 if (_settings_game.difficulty.industry_density == IndustryDensity::FundedOnly) {
2340 *min_number = 0;
2341 return 0;
2342 }
2343
2344 const IndustrySpec *ind_spc = GetIndustrySpec(it);
2345 uint8_t chance = ind_spc->appear_ingame[to_underlying(_settings_game.game_creation.landscape)];
2346 if (!ind_spc->enabled || ind_spc->layouts.empty() ||
2349 (chance = GetIndustryProbabilityCallback(it, IACT_RANDOMCREATION, chance)) == 0) {
2350 *min_number = 0;
2351 return 0;
2352 }
2353 *min_number = ind_spc->behaviour.Test(IndustryBehaviour::CanCloseLastInstance) ? 1 : 0;
2354 return chance;
2355}
2356
2362{
2363 /* Number of industries on a 256x256 map. */
2364 static const uint16_t numof_industry_table[] = {
2365 0, // none
2366 0, // minimal
2367 10, // very low
2368 25, // low
2369 55, // normal
2370 80, // high
2371 0, // custom
2372 };
2373
2374 assert(lengthof(numof_industry_table) == to_underlying(IndustryDensity::End));
2375 IndustryDensity density = (_game_mode != GM_EDITOR) ? _settings_game.difficulty.industry_density : IndustryDensity::VeryLow;
2376
2377 if (density == IndustryDensity::Custom) return std::min<uint>(IndustryPool::MAX_SIZE, _settings_game.game_creation.custom_industry_number);
2378
2379 return std::min<uint>(IndustryPool::MAX_SIZE, Map::ScaleBySize(numof_industry_table[to_underlying(density)]));
2380}
2381
2391static Industry *PlaceIndustry(IndustryType type, IndustryAvailabilityCallType creation_type, bool try_hard)
2392{
2393 uint tries = try_hard ? 10000u : 2000u;
2394 for (; tries > 0; tries--) {
2395 Industry *ind = CreateNewIndustry(RandomTile(), type, creation_type);
2396 if (ind != nullptr) return ind;
2397 }
2398 return nullptr;
2399}
2400
2407static void PlaceInitialIndustry(IndustryType type, bool water, bool try_hard)
2408{
2410
2412 PlaceIndustry(type, IACT_MAPGENERATION, try_hard);
2413
2414 cur_company.Restore();
2415}
2416
2422{
2423 uint total = 0;
2424 for (const auto &industries : Industry::industries) {
2425 total += static_cast<uint16_t>(std::size(industries));
2426 }
2427 return total;
2428}
2429
2430
2433{
2434 this->probability = 0;
2435 this->min_number = 0;
2436 this->target_count = 0;
2437 this->max_wait = 1;
2438 this->wait_count = 0;
2439}
2440
2443{
2445
2446 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2447 this->builddata[it].Reset();
2448 }
2449}
2450
2453{
2454 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.
2455 if (_settings_game.difficulty.industry_density == IndustryDensity::FundedOnly) return; // 'no industries' setting.
2456
2457 /* To prevent running out of unused industries for the player to connect,
2458 * add a fraction of new industries each month, but only if the manager can keep up. */
2459 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).
2460 if (GetCurrentTotalNumberOfIndustries() + max_behind >= (this->wanted_inds >> 16)) {
2461 this->wanted_inds += Map::ScaleBySize(NEWINDS_PER_MONTH);
2462 }
2463}
2464
2466 std::array<uint32_t, NUM_INDUSTRYTYPES> probs{};
2467 std::array<bool, NUM_INDUSTRYTYPES> force_one{};
2468 uint64_t total = 0;
2469 uint num_forced = 0;
2470};
2471
2478{
2480
2481 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2482 p.probs[it] = GetScaledIndustryGenerationProbability(it, water, &p.force_one[it]);
2483 p.total += p.probs[it];
2484 if (p.force_one[it]) p.num_forced++;
2485 }
2486
2487 return p;
2488}
2489
2495{
2496 if (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == IndustryDensity::FundedOnly) return; // No industries in the game.
2497
2498 /* Get the probabilities for all industries. This is done first as we need the total of
2499 * both land and water for scaling later. */
2502
2503 /* Run generation twice, for land and water industries in turn. */
2504 for (bool water = false;; water = true) {
2505 auto &p = water ? wprob : lprob;
2506
2507 /* Total number of industries scaled by land/water proportion. */
2508 uint total_amount = 0;
2509 if (lprob.total + wprob.total > 0) total_amount = p.total * GetNumberOfIndustries() / (lprob.total + wprob.total);
2510
2511 /* Scale land-based industries to the land proportion, unless the player has set a custom industry count. */
2512 if (!water && _settings_game.difficulty.industry_density != IndustryDensity::Custom) total_amount = Map::ScaleByLandProportion(total_amount);
2513
2514 /* Ensure that forced industries are generated even if the scaled amounts are too low. */
2515 if (p.total == 0 || total_amount < p.num_forced) {
2516 /* Only place the forced ones */
2517 total_amount = p.num_forced;
2518 }
2519
2521
2522 /* Try to build one industry per type independent of any probabilities */
2523 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2524 if (p.force_one[it]) {
2525 assert(total_amount > 0);
2526 total_amount--;
2527 PlaceInitialIndustry(it, water, true);
2528 }
2529 }
2530
2531 /* Add the remaining industries according to their probabilities */
2532 for (uint i = 0; i < total_amount; i++) {
2533 uint32_t r = RandomRange(p.total);
2534 IndustryType it = 0;
2535 while (r >= p.probs[it]) {
2536 r -= p.probs[it];
2537 it++;
2538 assert(it < NUM_INDUSTRYTYPES);
2539 }
2540 assert(p.probs[it] > 0);
2541 PlaceInitialIndustry(it, water, false);
2542 }
2543
2544 if (water) break;
2545 }
2546
2547 _industry_builder.Reset();
2548}
2549
2550template <>
2551Industry::ProducedHistory SumHistory(std::span<const Industry::ProducedHistory> history)
2552{
2553 uint32_t production = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const auto &p) { return r + p.production; });
2554 uint32_t transported = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const auto &p) { return r + p.transported; });
2555 auto count = std::size(history);
2556 return {.production = ClampTo<uint16_t>(production / count), .transported = ClampTo<uint16_t>(transported / count)};
2557}
2558
2559template <>
2560Industry::AcceptedHistory SumHistory(std::span<const Industry::AcceptedHistory> history)
2561{
2562 uint32_t accepted = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const auto &a) { return r + a.accepted; });
2563 uint32_t waiting = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const auto &a) { return r + a.waiting; });;
2564 auto count = std::size(history);
2565 return {.accepted = ClampTo<uint16_t>(accepted / count), .waiting = ClampTo<uint16_t>(waiting / count)};
2566}
2567
2573{
2574 auto month = TimerGameEconomy::month;
2575 UpdateValidHistory(i->valid_history, HISTORY_YEAR, month);
2576
2577 for (auto &p : i->produced) {
2578 if (IsValidCargoType(p.cargo)) {
2579 if (p.history[THIS_MONTH].production != 0) i->last_prod_year = TimerGameEconomy::year;
2580
2581 RotateHistory(p.history, i->valid_history, HISTORY_YEAR, month);
2582 }
2583 }
2584
2585 for (auto &a : i->accepted) {
2586 if (!IsValidCargoType(a.cargo)) continue;
2587 if (a.history == nullptr) continue;
2588
2589 (*a.history)[THIS_MONTH].waiting = GetAndResetAccumulatedAverage<uint16_t>(a.accumulated_waiting);
2590 RotateHistory(*a.history, i->valid_history, HISTORY_YEAR, month);
2591 }
2592}
2593
2599{
2600 const IndustrySpec *indspec = GetIndustrySpec(this->type);
2601 assert(indspec->UsesOriginalEconomy());
2602
2603 /* Rates are rounded up, so e.g. oilrig always produces some passengers */
2604 for (auto &p : this->produced) {
2605 p.rate = ClampTo<uint8_t>(CeilDiv(indspec->production_rate[&p - this->produced.data()] * this->prod_level, PRODLEVEL_DEFAULT));
2606 }
2607}
2608
2609void Industry::FillCachedName() const
2610{
2611 auto tmp_params = MakeParameters(this->index);
2612 this->cached_name = GetStringWithArgs(STR_INDUSTRY_NAME, tmp_params);
2613}
2614
2615void ClearAllIndustryCachedNames()
2616{
2617 for (Industry *ind : Industry::Iterate()) {
2618 ind->cached_name.clear();
2619 }
2620}
2621
2628{
2629 uint8_t min_number;
2631 bool changed = min_number != this->min_number || probability != this->probability;
2632 this->min_number = min_number;
2633 this->probability = probability;
2634 return changed;
2635}
2636
2639{
2640 bool changed = false;
2641 uint num_planned = 0; // Number of industries planned in the industry build data.
2642 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2643 changed |= this->builddata[it].GetIndustryTypeData(it);
2644 num_planned += this->builddata[it].target_count;
2645 }
2646 uint total_amount = this->wanted_inds >> 16; // Desired total number of industries.
2647 changed |= num_planned != total_amount;
2648 if (!changed) return; // All industries are still the same, no need to re-randomize.
2649
2650 /* Initialize the target counts. */
2651 uint force_build = 0; // Number of industries that should always be available.
2652 uint32_t total_prob = 0; // Sum of probabilities.
2653 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2654 IndustryTypeBuildData *ibd = this->builddata + it;
2655 force_build += ibd->min_number;
2656 ibd->target_count = ibd->min_number;
2657 total_prob += ibd->probability;
2658 }
2659
2660 if (total_prob == 0) return; // No buildable industries.
2661
2662 /* Subtract forced industries from the number of industries available for construction. */
2663 total_amount = (total_amount <= force_build) ? 0 : total_amount - force_build;
2664
2665 /* Assign number of industries that should be aimed for, by using the probability as a weight. */
2666 while (total_amount > 0) {
2667 uint32_t r = RandomRange(total_prob);
2668 IndustryType it = 0;
2669 while (r >= this->builddata[it].probability) {
2670 r -= this->builddata[it].probability;
2671 it++;
2672 assert(it < NUM_INDUSTRYTYPES);
2673 }
2674 assert(this->builddata[it].probability > 0);
2675 this->builddata[it].target_count++;
2676 total_amount--;
2677 }
2678}
2679
2684{
2685 this->SetupTargetCount();
2686
2687 int missing = 0; // Number of industries that need to be build.
2688 uint count = 0; // Number of industry types eligible for build.
2689 uint32_t total_prob = 0; // Sum of probabilities.
2690 IndustryType forced_build = NUM_INDUSTRYTYPES; // Industry type that should be forcibly build.
2691 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2692 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
2693 missing += difference;
2694 if (this->builddata[it].wait_count > 0) continue; // This type may not be built now.
2695 if (difference > 0) {
2696 if (Industry::GetIndustryTypeCount(it) == 0 && this->builddata[it].min_number > 0) {
2697 /* An industry that should exist at least once, is not available. Force it, trying the most needed one first. */
2698 if (forced_build == NUM_INDUSTRYTYPES ||
2699 difference > this->builddata[forced_build].target_count - Industry::GetIndustryTypeCount(forced_build)) {
2700 forced_build = it;
2701 }
2702 }
2703 total_prob += difference;
2704 count++;
2705 }
2706 }
2707
2708 if (EconomyIsInRecession() || (forced_build == NUM_INDUSTRYTYPES && (missing <= 0 || total_prob == 0))) count = 0; // Skip creation of an industry.
2709
2710 if (count >= 1) {
2711 /* If not forced, pick a weighted random industry to build.
2712 * For the case that count == 1, there is no need to draw a random number. */
2713 IndustryType it;
2714 if (forced_build != NUM_INDUSTRYTYPES) {
2715 it = forced_build;
2716 } else {
2717 /* Non-forced, select an industry type to build (weighted random). */
2718 uint32_t r = 0; // Initialized to silence the compiler.
2719 if (count > 1) r = RandomRange(total_prob);
2720 for (it = 0; it < NUM_INDUSTRYTYPES; it++) {
2721 if (this->builddata[it].wait_count > 0) continue; // Type may not be built now.
2722 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
2723 if (difference <= 0) continue; // Too many of this kind.
2724 if (count == 1) break;
2725 if (r < (uint)difference) break;
2726 r -= difference;
2727 }
2728 assert(it < NUM_INDUSTRYTYPES && this->builddata[it].target_count > Industry::GetIndustryTypeCount(it));
2729 }
2730
2731 /* Try to create the industry. */
2732 const Industry *ind = PlaceIndustry(it, IACT_RANDOMCREATION, false);
2733 if (ind == nullptr) {
2734 this->builddata[it].wait_count = this->builddata[it].max_wait + 1; // Compensate for decrementing below.
2735 this->builddata[it].max_wait = std::min(1000, this->builddata[it].max_wait + 2);
2736 } else {
2738 this->builddata[it].max_wait = std::max(this->builddata[it].max_wait / 2, 1); // Reduce waiting time of the industry type.
2739 }
2740 }
2741
2742 /* Decrement wait counters. */
2743 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2744 if (this->builddata[it].wait_count > 0) this->builddata[it].wait_count--;
2745 }
2746}
2747
2756static bool CheckIndustryCloseDownProtection(IndustryType type)
2757{
2758 const IndustrySpec *indspec = GetIndustrySpec(type);
2759
2760 /* oil wells (or the industries with that flag set) are always allowed to closedown */
2761 if (indspec->behaviour.Test(IndustryBehaviour::DontIncrProd) && _settings_game.game_creation.landscape == LandscapeType::Temperate) return false;
2763}
2764
2774static void CanCargoServiceIndustry(CargoType cargo, Industry *ind, bool *c_accepts, bool *c_produces)
2775{
2776 if (!IsValidCargoType(cargo)) return;
2777
2778 /* Check for acceptance of cargo */
2779 if (ind->IsCargoAccepted(cargo) && !IndustryTemporarilyRefusesCargo(ind, cargo)) *c_accepts = true;
2780
2781 /* Check for produced cargo */
2782 if (ind->IsCargoProduced(cargo)) *c_produces = true;
2783}
2784
2799{
2800 if (ind->stations_near.empty()) return 0; // No stations found at all => nobody services
2801
2802 int result = 0;
2803 for (const Vehicle *v : Vehicle::Iterate()) {
2804 /* Is it worthwhile to try this vehicle? */
2805 if (v->owner != _local_company && result != 0) continue;
2806
2807 /* Check whether it accepts the right kind of cargo */
2808 bool c_accepts = false;
2809 bool c_produces = false;
2810 if (v->type == VEH_TRAIN && v->IsFrontEngine()) {
2811 for (const Vehicle *u = v; u != nullptr; u = u->Next()) {
2812 CanCargoServiceIndustry(u->cargo_type, ind, &c_accepts, &c_produces);
2813 }
2814 } else if (v->type == VEH_ROAD || v->type == VEH_SHIP || v->type == VEH_AIRCRAFT) {
2815 CanCargoServiceIndustry(v->cargo_type, ind, &c_accepts, &c_produces);
2816 } else {
2817 continue;
2818 }
2819 if (!c_accepts && !c_produces) continue; // Wrong cargo
2820
2821 /* Check orders of the vehicle.
2822 * We cannot check the first of shared orders only, since the first vehicle in such a chain
2823 * may have a different cargo type.
2824 */
2825 for (const Order &o : v->Orders()) {
2826 if (o.IsType(OT_GOTO_STATION) && o.GetUnloadType() != OrderUnloadType::Transfer) {
2827 /* Vehicle visits a station to load or unload */
2828 Station *st = Station::Get(o.GetDestination().ToStationID());
2829 assert(st != nullptr);
2830
2831 /* Same cargo produced by industry is dropped here => not serviced by vehicle v */
2832 if (o.GetUnloadType() == OrderUnloadType::Unload && !c_accepts) break;
2833
2834 if (ind->stations_near.find(st) != ind->stations_near.end()) {
2835 if (v->owner == _local_company) return 2; // Company services industry
2836 result = 1; // Competitor services industry
2837 }
2838 }
2839 }
2840 }
2841 return result;
2842}
2843
2851static void ReportNewsProductionChangeIndustry(Industry *ind, CargoType cargo, int percent)
2852{
2853 NewsType nt;
2854
2855 switch (WhoCanServiceIndustry(ind)) {
2856 case 0: nt = NewsType::IndustryNobody; break;
2857 case 1: nt = NewsType::IndustryOther; break;
2858 case 2: nt = NewsType::IndustryCompany; break;
2859 default: NOT_REACHED();
2860 }
2861 AddIndustryNewsItem(
2862 GetEncodedString(percent >= 0 ? STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH : STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH,
2863 CargoSpec::Get(cargo)->name, ind->index, abs(percent)
2864 ),
2865 nt,
2866 ind->index
2867 );
2868}
2869
2870static const uint PERCENT_TRANSPORTED_60 = 153;
2871static const uint PERCENT_TRANSPORTED_80 = 204;
2872
2878static void ChangeIndustryProduction(Industry *i, bool monthly)
2879{
2880 StringID str = STR_NULL;
2881 bool closeit = false;
2882 const IndustrySpec *indspec = GetIndustrySpec(i->type);
2883 bool standard = false;
2884 bool suppress_message = false;
2885 bool recalculate_multipliers = false;
2886 /* use original economy for industries using production related callbacks */
2887 bool original_economy = indspec->UsesOriginalEconomy();
2888 uint8_t div = 0;
2889 uint8_t mul = 0;
2890 int8_t increment = 0;
2891
2893 if (callback_enabled) {
2894 std::array<int32_t, 1> regs100;
2895 uint16_t res = GetIndustryCallback(monthly ? CBID_INDUSTRY_MONTHLYPROD_CHANGE : CBID_INDUSTRY_PRODUCTION_CHANGE, 0, Random(), i, i->type, i->location.tile, regs100);
2896 if (res != CALLBACK_FAILED) { // failed callback means "do nothing"
2897 suppress_message = HasBit(res, 7);
2898 /* Get the custom message if any */
2899 if (HasBit(res, 8)) str = MapGRFStringID(indspec->grf_prop.grfid, GRFStringID(GB(regs100[0], 0, 16)));
2900 res = GB(res, 0, 4);
2901 switch (res) {
2902 default: NOT_REACHED();
2903 case 0x0: break; // Do nothing, but show the custom message if any
2904 case 0x1: div = 1; break; // Halve industry production. If production reaches the quarter of the default, the industry is closed instead.
2905 case 0x2: mul = 1; break; // Double industry production if it hasn't reached eight times of the original yet.
2906 case 0x3: closeit = true; break; // The industry announces imminent closure, and is physically removed from the map next month.
2907 case 0x4: standard = true; break; // Do the standard random production change as if this industry was a primary one.
2908 case 0x5: case 0x6: case 0x7: // Divide production by 4, 8, 16
2909 case 0x8: div = res - 0x3; break; // Divide production by 32
2910 case 0x9: case 0xA: case 0xB: // Multiply production by 4, 8, 16
2911 case 0xC: mul = res - 0x7; break; // Multiply production by 32
2912 case 0xD: // decrement production
2913 case 0xE: // increment production
2914 increment = res == 0x0D ? -1 : 1;
2915 break;
2916 case 0xF: // Set production to third byte of register 0x100
2917 i->prod_level = Clamp(GB(regs100[0], 16, 8), PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
2918 recalculate_multipliers = true;
2919 break;
2920 }
2921 }
2922 } else {
2923 if (monthly == original_economy) return;
2924 if (!original_economy && _settings_game.economy.type == EconomyType::Frozen) return;
2925 if (indspec->life_type == INDUSTRYLIFE_BLACK_HOLE) return;
2926 }
2927
2928 if (standard || (!callback_enabled && indspec->life_type.Any({IndustryLifeType::Organic, IndustryLifeType::Extractive}))) {
2929 /* decrease or increase */
2930 bool only_decrease = indspec->behaviour.Test(IndustryBehaviour::DontIncrProd) && _settings_game.game_creation.landscape == LandscapeType::Temperate;
2931
2932 if (original_economy) {
2933 if (only_decrease || Chance16(1, 3)) {
2934 /* If more than 60% transported, 66% chance of increase, else 33% chance of increase */
2935 if (!only_decrease && (i->GetProduced(0).history[LAST_MONTH].PctTransported() > PERCENT_TRANSPORTED_60) != Chance16(1, 3)) {
2936 mul = 1; // Increase production
2937 } else {
2938 div = 1; // Decrease production
2939 }
2940 }
2941 } else if (_settings_game.economy.type == EconomyType::Smooth) {
2943 for (auto &p : i->produced) {
2944 if (!IsValidCargoType(p.cargo)) continue;
2945 uint32_t r = Random();
2946 int old_prod, new_prod, percent;
2947 /* If over 60% is transported, mult is 1, else mult is -1. */
2948 int mult = (p.history[LAST_MONTH].PctTransported() > PERCENT_TRANSPORTED_60) ? 1 : -1;
2949
2950 new_prod = old_prod = p.rate;
2951
2952 /* For industries with only_decrease flags (temperate terrain Oil Wells),
2953 * the multiplier will always be -1 so they will only decrease. */
2954 if (only_decrease) {
2955 mult = -1;
2956 /* For normal industries, if over 60% is transported, 33% chance for decrease.
2957 * Bonus for very high station ratings (over 80%): 16% chance for decrease. */
2958 } else if (Chance16I(1, ((p.history[LAST_MONTH].PctTransported() > PERCENT_TRANSPORTED_80) ? 6 : 3), r)) {
2959 mult *= -1;
2960 }
2961
2962 /* 4.5% chance for 3-23% (or 1 unit for very low productions) production change,
2963 * determined by mult value. If mult = 1 prod. increases, else (-1) it decreases. */
2964 if (Chance16I(1, 22, r >> 16)) {
2965 new_prod += mult * (std::max(((RandomRange(50) + 10) * old_prod) >> 8, 1U));
2966 }
2967
2968 /* Prevent production to overflow or Oil Rig passengers to be over-"produced" */
2969 new_prod = Clamp(new_prod, 1, 255);
2970 if (IsValidCargoType(p.cargo) && p.cargo == GetCargoTypeByLabel(CT_PASSENGERS) && !indspec->behaviour.Test(IndustryBehaviour::NoPaxProdClamp)) {
2971 new_prod = Clamp(new_prod, 0, 16);
2972 }
2973
2974 /* If override flags are set, prevent actually changing production if any was decided on */
2975 if (i->ctlflags.Test(IndustryControlFlag::NoProductionDecrease) && new_prod < old_prod) continue;
2976 if (i->ctlflags.Test(IndustryControlFlag::NoProductionIncrease) && new_prod > old_prod) continue;
2977
2978 /* Do not stop closing the industry when it has the lowest possible production rate */
2979 if (new_prod == old_prod && old_prod > 1) {
2980 closeit = false;
2981 continue;
2982 }
2983
2984 percent = (old_prod == 0) ? 100 : (new_prod * 100 / old_prod - 100);
2985 p.rate = new_prod;
2986
2987 /* Close the industry when it has the lowest possible production rate */
2988 if (new_prod > 1) closeit = false;
2989
2990 if (abs(percent) >= 10) {
2991 ReportNewsProductionChangeIndustry(i, p.cargo, percent);
2992 }
2993 }
2994 }
2995 }
2996
2997 /* If override flags are set, prevent actually changing production if any was decided on */
2998 if (i->ctlflags.Test(IndustryControlFlag::NoProductionDecrease) && (div > 0 || increment < 0)) return;
2999 if (i->ctlflags.Test(IndustryControlFlag::NoProductionIncrease) && (mul > 0 || increment > 0)) return;
3001 div = 0;
3002 mul = 0;
3003 increment = 0;
3004 }
3005
3006 if (!callback_enabled && indspec->life_type.Test(IndustryLifeType::Processing)) {
3007 if (TimerGameEconomy::year - i->last_prod_year >= PROCESSING_INDUSTRY_ABANDONMENT_YEARS && Chance16(1, original_economy ? 2 : 180)) {
3008 closeit = true;
3009 }
3010 }
3011
3012 /* Increase if needed */
3013 while (mul-- != 0 && i->prod_level < PRODLEVEL_MAXIMUM) {
3014 i->prod_level = std::min<int>(i->prod_level * 2, PRODLEVEL_MAXIMUM);
3015 recalculate_multipliers = true;
3016 if (str == STR_NULL) str = indspec->production_up_text;
3017 }
3018
3019 /* Decrease if needed */
3020 while (div-- != 0 && !closeit) {
3021 if (i->prod_level == PRODLEVEL_MINIMUM) {
3022 closeit = true;
3023 break;
3024 } else {
3025 i->prod_level = std::max<int>(i->prod_level / 2, PRODLEVEL_MINIMUM);
3026 recalculate_multipliers = true;
3027 if (str == STR_NULL) str = indspec->production_down_text;
3028 }
3029 }
3030
3031 /* Increase or Decreasing the production level if needed */
3032 if (increment != 0) {
3033 if (increment < 0 && i->prod_level == PRODLEVEL_MINIMUM) {
3034 closeit = true;
3035 } else {
3037 recalculate_multipliers = true;
3038 }
3039 }
3040
3041 /* Recalculate production_rate
3042 * For non-smooth economy these should always be synchronized with prod_level */
3043 if (recalculate_multipliers) i->RecomputeProductionMultipliers();
3044
3045 /* Close if needed and allowed */
3049 str = indspec->closure_text;
3050 }
3051
3052 if (!suppress_message && str != STR_NULL) {
3053 NewsType nt;
3054 /* Compute news category */
3055 if (closeit) {
3057 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index));
3058 Game::NewEvent(new ScriptEventIndustryClose(i->index));
3059 } else {
3060 switch (WhoCanServiceIndustry(i)) {
3061 case 0: nt = NewsType::IndustryNobody; break;
3062 case 1: nt = NewsType::IndustryOther; break;
3063 case 2: nt = NewsType::IndustryCompany; break;
3064 default: NOT_REACHED();
3065 }
3066 }
3067 /* Set parameters of news string */
3068 EncodedString headline;
3069 if (str > STR_LAST_STRINGID) {
3070 headline = GetEncodedString(str, STR_TOWN_NAME, i->town->index, indspec->name);
3071 } else if (closeit) {
3072 headline = GetEncodedString(str, STR_FORMAT_INDUSTRY_NAME, i->town->index, indspec->name);
3073 } else {
3074 headline = GetEncodedString(str, i->index);
3075 }
3076 /* and report the news to the user */
3077 if (closeit) {
3078 AddTileNewsItem(std::move(headline), nt, i->location.tile + TileDiffXY(1, 1));
3079 } else {
3080 AddIndustryNewsItem(std::move(headline), nt, i->index);
3081 }
3082 }
3083}
3084
3092static const IntervalTimer<TimerGameEconomy> _economy_industries_daily({TimerGameEconomy::Trigger::Day, TimerGameEconomy::Priority::Industry}, [](auto)
3093{
3094 _economy.industry_daily_change_counter += _economy.industry_daily_increment;
3095
3096 /* Bits 16-31 of industry_construction_counter contain the number of industries to change/create today,
3097 * the lower 16 bit are a fractional part that might accumulate over several days until it
3098 * is sufficient for an industry. */
3099 uint16_t change_loop = _economy.industry_daily_change_counter >> 16;
3100
3101 /* Reset the active part of the counter, just keeping the "fractional part" */
3102 _economy.industry_daily_change_counter &= 0xFFFF;
3103
3104 if (change_loop == 0) {
3105 return; // Nothing to do? get out
3106 }
3107
3109
3110 /* perform the required industry changes for the day */
3111
3112 uint perc = 3; // Between 3% and 9% chance of creating a new industry.
3113 if ((_industry_builder.wanted_inds >> 16) > GetCurrentTotalNumberOfIndustries()) {
3114 perc = std::min(9u, perc + (_industry_builder.wanted_inds >> 16) - GetCurrentTotalNumberOfIndustries());
3115 }
3116 for (uint16_t j = 0; j < change_loop; j++) {
3117 if (Chance16(perc, 100)) {
3118 _industry_builder.TryBuildNewIndustry();
3119 } else {
3121 if (i != nullptr) {
3122 ChangeIndustryProduction(i, false);
3124 }
3125 }
3126 }
3127
3128 cur_company.Restore();
3129
3130 /* production-change */
3131 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, IDIWD_PRODUCTION_CHANGE);
3132});
3133
3134static const IntervalTimer<TimerGameEconomy> _economy_industries_monthly({TimerGameEconomy::Trigger::Month, TimerGameEconomy::Priority::Industry}, [](auto)
3135{
3137
3138 _industry_builder.EconomyMonthlyLoop();
3139
3140 for (Industry *i : Industry::Iterate()) {
3142 if (i->prod_level == PRODLEVEL_CLOSURE) {
3143 delete i;
3144 } else {
3145 ChangeIndustryProduction(i, true);
3147 }
3148 }
3149
3150 cur_company.Restore();
3151
3152 /* production-change */
3153 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, IDIWD_PRODUCTION_CHANGE);
3154});
3155
3156
3157void InitializeIndustries()
3158{
3159 Industry::industries.fill({});
3160 _industry_sound_tile = TileIndex{};
3161
3162 _industry_builder.Reset();
3163}
3164
3167{
3168 int count = 0;
3169 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
3170 if (Industry::GetIndustryTypeCount(it) > 0) continue; // Types of existing industries can be skipped.
3171
3172 bool force_at_least_one;
3173 uint32_t chance = GetScaledIndustryGenerationProbability(it, std::nullopt, &force_at_least_one);
3174 if (chance == 0 || !force_at_least_one) continue; // Types that are not available can be skipped.
3175
3176 const IndustrySpec *is = GetIndustrySpec(it);
3177 ShowErrorMessage(GetEncodedString(STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES, is->name),
3178 GetEncodedString(STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION), WL_WARNING);
3179
3180 count++;
3181 if (count >= 3) break; // Don't swamp the user with errors.
3182 }
3183}
3184
3193
3199{
3200 /* Lumber mills are neither raw nor processing */
3201 return this->life_type.Test(IndustryLifeType::Processing) &&
3203}
3204
3210{
3211 /* Building raw industries like secondary uses different price base */
3212 return (_price[(_settings_game.construction.raw_industry_construction == 1 && this->IsRawIndustry()) ?
3213 Price::BuildIndustryRaw : Price::BuildIndustry] * this->cost_multiplier) >> 8;
3214}
3215
3223{
3225}
3226
3241
3243static CommandCost TerraformTile_Industry(TileIndex tile, DoCommandFlags flags, int z_new, Slope tileh_new)
3244{
3245 if (AutoslopeEnabled()) {
3246 /* We imitate here TTDP's behaviour:
3247 * - Both new and old slope must not be steep.
3248 * - TileMaxZ must not be changed.
3249 * - Allow autoslope by default.
3250 * - Disallow autoslope if callback succeeds and returns non-zero.
3251 */
3252 Slope tileh_old = GetTileSlope(tile);
3253 /* TileMaxZ must not be changed. Slopes must not be steep. */
3254 if (!IsSteepSlope(tileh_old) && !IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) {
3255 const IndustryGfx gfx = GetIndustryGfx(tile);
3256 const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
3257
3258 /* Call callback 3C 'disable autosloping for industry tiles'. */
3260 /* If the callback fails, allow autoslope. */
3261 uint16_t res = GetIndustryTileCallback(CBID_INDTILE_AUTOSLOPE, 0, 0, gfx, Industry::GetByTile(tile), tile);
3263 } else {
3264 /* allow autoslope */
3266 }
3267 }
3268 }
3269 return Command<Commands::LandscapeClear>::Do(flags, tile);
3270}
3271
3274 .draw_tile_proc = DrawTile_Industry,
3275 .get_slope_pixel_z_proc = [](TileIndex tile, uint, uint, bool) { return GetTileMaxPixelZ(tile); },
3276 .clear_tile_proc = ClearTile_Industry,
3277 .add_accepted_cargo_proc = AddAcceptedCargo_Industry,
3278 .get_tile_desc_proc = GetTileDesc_Industry,
3279 .click_tile_proc = ClickTile_Industry,
3280 .animate_tile_proc = AnimateTile_Industry,
3281 .tile_loop_proc = TileLoop_Industry,
3282 .change_tile_owner_proc = ChangeTileOwner_Industry,
3283 .get_foundation_proc = GetFoundation_Industry,
3284 .terraform_tile_proc = TerraformTile_Industry,
3285};
3286
3287bool IndustryCompare::operator() (const IndustryListEntry &lhs, const IndustryListEntry &rhs) const
3288{
3289 /* Compare by distance first and use index as a tiebreaker. */
3290 return std::tie(lhs.distance, lhs.industry->index) < std::tie(rhs.distance, rhs.industry->index);
3291}
3292
3298{
3299 auto ita = std::find_if(std::rbegin(ind->accepted), std::rend(ind->accepted), [](const auto &a) { return IsValidCargoType(a.cargo); });
3300 ind->accepted.erase(ita.base(), std::end(ind->accepted));
3301 ind->accepted.shrink_to_fit();
3302
3303 auto itp = std::find_if(std::rbegin(ind->produced), std::rend(ind->produced), [](const auto &p) { return IsValidCargoType(p.cargo); });
3304 ind->produced.erase(itp.base(), std::end(ind->produced));
3305 ind->produced.shrink_to_fit();
3306}
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.
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
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:21
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:108
static constexpr CargoLabel CT_PASSENGERS
Available types of cargo Labels may be re-used between different climates.
Definition cargo_type.h:29
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.
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.
static void NewEvent(class ScriptEvent *event)
Queue a new event for the game script.
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
Generate TileIndices around a center tile or tile area, with increasing distance.
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
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 Month month
Current month (0..11).
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:65
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:234
IndustryID GetIndustryIndexOfField(Tile t)
Get the industry (farm) that made the field.
Definition clear_map.h:189
@ Desert
Desert with transition (1,3).
Definition clear_map.h:26
@ Fields
Farm fields (3).
Definition clear_map.h:25
@ Rough
Rough mounds (3).
Definition clear_map.h:23
ClearGround GetClearGround(Tile t)
Get the type of clear tile.
Definition clear_map.h:52
void SetIndustryIndexOfField(Tile t, IndustryID i)
Set the industry (farm) that made the field.
Definition clear_map.h:201
void MakeField(Tile t, uint field_type, IndustryID industry)
Make a (farm) field tile.
Definition clear_map.h:274
void SetClearCounter(Tile t, uint c)
Sets the counter used to advance to the next clear density/field type.
Definition clear_map.h:138
uint GetFence(Tile t, DiagDirection side)
Is there a fence at the given border?
Definition clear_map.h:215
bool IsSnowTile(Tile t)
Test if a tile is covered with snow.
Definition clear_map.h:40
CommandCost CommandCostWithParam(StringID str, uint64_t value)
Return an error status, with string and parameter.
Definition command.cpp:416
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ Auto
don't allow building on structures
@ NoModifyTownRating
do not change town rating
@ NoWater
don't allow building on water
@ Execute
execute the given command
@ NoTestTownRating
town rating does not disallow you from building
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.
Prices _price
Prices and also the fractional part.
Definition economy.cpp:106
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.
@ Original
Imitates original TTD economy.
@ Frozen
Stops production changes and industry closures.
@ Smooth
Makes production changes more often, and in smaller steps.
@ EXPENSES_CONSTRUCTION
Construction costs.
@ EXPENSES_OTHER
Other expenses.
@ BuildIndustryRaw
Price for funding new raw industries, e.g. coal mine, forest.
@ BuildFoundation
Price for building foundation under other constructions e.g. roads, rails, depots,...
@ BuildIndustry
Price for funding new industries.
@ ClearIndustry
Price for destroying industries.
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:21
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_LAND_INDUSTRY
Generate industries.
Definition genworld.h:65
@ GWP_WATER_INDUSTRY
Generate industries.
Definition genworld.h:66
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.
void UpdateValidHistory(ValidHistoryMask &valid_history, const HistoryRange &hr, uint cur_month)
Update mask of valid records for a historical data.
Definition history.cpp:25
Functions for storing historical data.
T GetAndResetAccumulatedAverage(Taccrued &total)
Get an average value for the previous month, as reset for the next month.
void RotateHistory(HistoryData< T > &history, ValidHistoryMask valid_history, const HistoryRange &hr, uint cur_month)
Rotate historical data.
Types for storing historical data.
Base of all industries.
static constexpr uint8_t PRODLEVEL_MAXIMUM
the industry is running at full speed
Definition industry.h:38
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:37
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:28
IndustryBuildData _industry_builder
In-game manager of industries.
static constexpr uint8_t PRODLEVEL_MINIMUM
below this level, the industry is set to be closing
Definition industry.h:36
static constexpr uint8_t PRODLEVEL_CLOSURE
signal set to actually close the industry
Definition industry.h:35
@ ExternalProdLevel
Indicates that the production level of the industry is externally controlled.
Definition industry.h:54
@ NoClosure
Industry can not close regardless of production level or time since last delivery.
Definition industry.h:52
@ NoProductionDecrease
When industry production change is evaluated, rolls to decrease are ignored.
Definition industry.h:46
@ NoProductionIncrease
When industry production change is evaluated, rolls to increase are ignored.
Definition industry.h:48
static bool ClickTile_Industry(TileIndex tile)
Tile callback function signature for clicking a tile.
const TileTypeProcs _tile_type_industry_procs
TileTypeProcs definitions for TileType::Industry tiles.
Definition landscape.cpp:60
static uint16_t GetIndustryGamePlayProbability(IndustryType it, uint8_t *min_number)
Compute the probability for constructing a new industry during game play.
static void TileLoop_Industry(TileIndex tile)
Tile callback function signature for running periodic tile updates.
static CommandCost CheckNewIndustry_Water(TileIndex tile)
Check the conditions of CHECK_WATER (Industry should be in the desert).
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 IndustryGenerationProbabilities GetScaledProbabilities(bool water)
Get scaled industry generation probabilities.
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 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 uint32_t GetScaledIndustryGenerationProbability(IndustryType it, std::optional< bool > water, bool *force_at_least_one)
Compute the appearance probability for an industry during map creation.
static bool CheckScaledDistanceFromEdge(TileIndex tile, uint maxdist)
Check if a tile is within a distance from map edges, scaled by map dimensions independently.
static void ReportNewsProductionChangeIndustry(Industry *ind, CargoType cargo, int percent)
Report news that industry production has changed significantly.
static const IntervalTimer< TimerGameEconomy > _economy_industries_daily({TimerGameEconomy::Trigger::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,...
static void GetTileDesc_Industry(TileIndex tile, TileDesc &td)
Tile callback function signature for obtaining a tile description.
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?
static Foundation GetFoundation_Industry(TileIndex tile, Slope tileh)
Tile callback function signature for getting the foundation of a tile.
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.
static void ChangeTileOwner_Industry(TileIndex tile, Owner old_owner, Owner new_owner)
Tile callback function signature for changing the owner of a tile.
static Industry * PlaceIndustry(IndustryType type, IndustryAvailabilityCallType creation_type, bool try_hard)
Try to place the industry in the game.
static bool IsSuitableForFarmField(TileIndex tile, bool allow_fields, bool allow_rough)
Check whether the tile can be replaced by a farm field.
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 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.
static void AddAcceptedCargo_Industry(TileIndex tile, CargoArray &acceptance, CargoTypes &always_accepted)
Tile callback function signature for obtaining cargo acceptance of a tile.
CommandCost CmdBuildIndustry(DoCommandFlags flags, TileIndex tile, IndustryType it, uint32_t first_layout, bool fund, uint32_t seed)
Build/Fund an industry.
static CommandCost ClearTile_Industry(TileIndex tile, DoCommandFlags flags)
Tile callback function signature for clearing a tile.
static void PlaceInitialIndustry(IndustryType type, bool water, bool try_hard)
Try to build a industry on the map.
static bool CheckIndustryCloseDownProtection(IndustryType type)
Protects an industry from closure if the appropriate flags and conditions are met CanCloseLastInstanc...
static CommandCost TerraformTile_Industry(TileIndex tile, DoCommandFlags flags, int z_new, Slope tileh_new)
Tile callback function signature of the terraforming callback.
static void AnimateTile_Industry(TileIndex tile)
Tile callback function signature for animating a tile.
static void DrawTile_Industry(TileInfo *ti)
Tile callback function signature for drawing a tile and its contents to the screen.
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.
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 uint8_t _industry_anim_offs_toffee[]
This is ONLY used for Toffee Quarry.
static const DrawIndustryCoordinates _coal_plant_sparks[]
Movement of the sparks , only used for Power Station.
static const DrawIndustryAnimationStruct _draw_industry_spec1[96]
This is ONLY used for Sugar Mine.
static const uint8_t _industry_anim_offs_bubbles[]
This is ONLY used for the Bubble Generator.
static const DrawBuildingsTileStruct _industry_draw_tile_data[NEW_INDUSTRYTILEOFFSET *4]
Structure for industry tiles drawing.
static const DrawIndustryCoordinates _drawtile_proc1[5]
This is ONLY used for Sugar Mine.
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
@ IndustryTick
The industry has been triggered via its tick.
@ TileLoop
The tile of the industry has been triggered during the tileloop.
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
@ CargoDistributed
Trigger when cargo is distributed.
@ IndustryTick
Trigger every tick.
@ TileLoop
Trigger in the periodic tile loop.
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.).
@ Arctic
Landscape with snow levels.
@ Tropic
Landscape with distinct rainforests and deserts,.
@ Temperate
Base landscape.
uint DistanceMax(TileIndex t0, TileIndex t1)
Gets the biggest distance component (x or y) between the two given tiles.
Definition map.cpp:201
uint DistanceFromEdgeDir(TileIndex tile, DiagDirection dir)
Gets the distance to the edge of the map in given direction.
Definition map.cpp:246
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:120
Functions related to maps.
TileIndex TileAddXY(TileIndex tile, int x, int y)
Adds a given offset to a tile.
Definition map_func.h:474
TileIndexDiff ToTileIndexDiff(TileIndexDiffC tidc)
Return the offset between two tiles from a TileIndexDiffC struct.
Definition map_func.h:444
TileIndexDiff TileDiffXY(int x, int y)
Calculates an offset for the given coordinate(-offset).
Definition map_func.h:392
TileIndexDiff TileOffsByAxis(Axis axis)
Convert an Axis to a TileIndexDiff.
Definition map_func.h:559
static uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:429
static uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:419
#define RandomTile()
Get a valid random tile.
Definition map_func.h:656
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition map_func.h:574
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.
constexpr To ClampTo(From value)
Clamp the given value down to lie within the requested type.
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 ...
const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET]
Extern declaration for _origin_industry_specs in table/build_industry.h.
@ NoAnimation
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.
uint16_t GetIndustryCallback(CallbackID callback, uint32_t param1, uint32_t param2, Industry *industry, IndustryType type, TileIndex tile, std::span< int32_t > regs100)
Perform an industry callback.
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.
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 TriggerIndustryTileRandomisation(TileIndex tile, IndustryRandomTrigger trigger)
Trigger a random trigger for a single industry tile.
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 TriggerIndustryRandomisation(Industry *ind, IndustryRandomTrigger trigger)
Trigger a random trigger for all industry tiles.
NewGRF handling of industry tiles.
StrongType::Typedef< uint32_t, struct GRFStringIDTag, StrongType::Compare, StrongType::Integer > GRFStringID
Type for GRF-internal string IDs.
Functions related to news.
void DeleteIndustryNews(IndustryID iid)
Remove news regarding given industry.
NewsType
Type of news.
Definition news_type.h:29
@ IndustryCompany
Production changes of industry serviced by local company.
Definition news_type.h:38
@ IndustryClose
Closing of industries.
Definition news_type.h:36
@ IndustryOpen
Opening of industries.
Definition news_type.h:35
@ IndustryNobody
Other industry production changes.
Definition news_type.h:40
@ IndustryOther
Production changes of industry serviced by competitor(s).
Definition news_type.h:39
Base for all objects.
@ Transfer
Transfer all cargo onto the platform.
Definition order_type.h:70
@ Unload
Force unloading all cargo onto the platform, possibly not getting paid.
Definition order_type.h:69
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:61
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
IndustryDensity
Available industry map generation densities.
@ FundedOnly
The game does not build industries.
@ End
Number of industry density settings.
@ VeryLow
Very few industries at game start.
@ Custom
Custom number of 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:47
@ SLOPE_W
the west corner of the tile is raised
Definition slope_type.h:49
@ SLOPE_E
the east corner of the tile is raised
Definition slope_type.h:51
@ SLOPE_S
the south corner of the tile is raised
Definition slope_type.h:50
@ SLOPE_N
the north corner of the tile is raised
Definition slope_type.h:52
@ SLOPE_SW
south and west corner are raised
Definition slope_type.h:55
@ SLOPE_FLAT
a flat tile
Definition slope_type.h:48
@ SLOPE_NE
north and east corner are raised
Definition slope_type.h:57
@ SLOPE_SE
south and east corner are raised
Definition slope_type.h:56
@ SLOPE_NW
north and west corner are raised
Definition slope_type.h:54
Foundation
Enumeration for Foundations.
Definition slope_type.h:92
@ FOUNDATION_LEVELED
The tile is leveled up to a flat slope.
Definition slope_type.h:94
@ FOUNDATION_NONE
The tile has no foundation, the slope remains unchanged.
Definition slope_type.h:93
Functions related to sound.
SoundFx
Sound effects from baseset.
Definition sound_type.h:46
@ SND_30_TOFFEE_QUARRY
48 == 0x30 Industry animation: toffee quarry: drill
Definition sound_type.h:96
@ SND_2E_BUBBLE_GENERATOR
46 == 0x2E Industry animation: bubble generator (1): generate bubble
Definition sound_type.h:94
@ SND_2D_SUGAR_MINE_1
45 == 0x2D Industry animation: sugar mine (1): shaking sieve
Definition sound_type.h:93
@ SND_2B_TOY_FACTORY_2
43 == 0x2B Industry animation: toy factory (2): stamp product
Definition sound_type.h:91
@ SND_38_LUMBER_MILL_1
56 == 0x38 Industry animation: lumber mill (1): chainsaw
Definition sound_type.h:104
@ SND_29_SUGAR_MINE_2
41 == 0x29 Industry animation: sugar mine (2): shaking sieve
Definition sound_type.h:89
@ SND_2C_TOY_FACTORY_1
44 == 0x2C Industry animation: toy factory (1): conveyor belt
Definition sound_type.h:92
@ SND_37_LUMBER_MILL_2
55 == 0x37 Industry animation: lumber mill (2): falling tree
Definition sound_type.h:103
@ SND_0C_POWER_STATION
10 == 0x0A Industry animation: power station: spark
Definition sound_type.h:58
@ SND_0B_MINE
9 == 0x09 Industry animation: coal/copper/gold mine: headgear
Definition sound_type.h:57
@ SND_36_LUMBER_MILL_3
54 == 0x36 Industry animation: lumber mill (3): crashing tree
Definition sound_type.h:102
@ SND_2A_TOY_FACTORY_3
42 == 0x2A Industry animation: toy factory (3): eject product
Definition sound_type.h:90
@ Industry
Source/destination is an industry.
Definition source_type.h:21
static PaletteID GetColourPalette(Colours colour)
Get recolour palette for a colour.
Definition sprite.h:221
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:188
PaletteID GroundSpritePaletteTransform(SpriteID image, PaletteID pal, PaletteID default_pal)
Applies PALETTE_MODIFIER_COLOUR to a palette entry of a ground sprite.
Definition sprite.h:207
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:90
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).
Class to backup a specific variable and restore it upon destruction of this object to prevent stack v...
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:115
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:138
This structure is the same for both Industries and Houses.
Definition sprite.h:90
uint8_t draw_proc
This allows to specify a special drawing procedure.
Definition sprite.h:93
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
A special vehicle is one of the following:
uint8_t animation_substate
Sub state to time the change of the graphics/behaviour.
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.
Data for managing the number and type of industries in the game.
Definition industry.h:307
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:309
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:308
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.
SubstituteGRFFileProps grf_prop
properties related to the grf file
StringID name
Displayed name of the industry.
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.
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.
Slope slopes_refused
slope pattern on which this tile cannot be built
AnimationInfo< IndustryAnimationTriggers > 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!).
SubstituteGRFFileProps grf_prop
properties related to the grf file
bool anim_state
When true, the tile has to be drawn using the animation state instead of the construction stage.
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:292
uint32_t probability
Relative probability of building this industry.
Definition industry.h:293
uint16_t target_count
Desired number of industries of this type.
Definition industry.h:295
uint8_t min_number
Smallest number of industries that should exist (either 0 or 1).
Definition industry.h:294
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:297
uint16_t max_wait
Starting number of turns to wait (copied to wait_count).
Definition industry.h:296
CargoType cargo
Cargo type.
Definition industry.h:86
CargoType cargo
Cargo type.
Definition industry.h:74
HistoryData< ProducedHistory > history
History of cargo produced and transported for this month and 24 previous months.
Definition industry.h:77
uint8_t rate
Production rate.
Definition industry.h:76
Defines the internal data of a functional industry.
Definition industry.h:62
static Industry * GetRandom()
Return a random valid industry.
IndustryType type
type of industry.
Definition industry.h:115
Owner exclusive_supplier
Which company has exclusive rights to deliver cargo (INVALID_OWNER = anyone).
Definition industry.h:130
TimerGameCalendar::Date construction_date
Date of the construction of the industry.
Definition industry.h:127
IndustryControlFlags ctlflags
flags overriding standard behaviours
Definition industry.h:120
bool IsCargoAccepted() const
Test if this industry accepts any cargo.
Definition industry.h:223
PersistentStorage * psa
Persistent storage for NewGRF industries.
Definition industry.h:136
uint8_t prod_level
general production level
Definition industry.h:112
Colours random_colour
randomized colour of the industry, for display purpose
Definition industry.h:117
void RecomputeProductionMultipliers()
Recompute production_rate for current prod_level.
EncodedString text
General text with additional information.
Definition industry.h:132
uint8_t construction_type
Way the industry was constructed (.
Definition industry.h:128
std::string cached_name
NOSAVE: Cache of the resolved name of the industry.
Definition industry.h:124
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:158
ValidHistoryMask valid_history
Mask of valid history records.
Definition industry.h:109
TimerGameEconomy::Year last_prod_year
last economy year of production
Definition industry.h:118
ProducedCargoes produced
produced cargo slots
Definition industry.h:110
uint16_t random
Random value used for randomisation of all kinds of things.
Definition industry.h:134
static void PostDestructor(size_t index)
Invalidating some stuff after removing item from the pool.
Town * town
Nearest town.
Definition industry.h:107
Owner founder
Founder of the industry.
Definition industry.h:126
uint8_t selected_layout
Which tile layout was used when creating the industry.
Definition industry.h:129
AcceptedCargoes accepted
accepted cargo slots
Definition industry.h:111
static uint16_t GetIndustryTypeCount(IndustryType type)
Get the count of industries for this type.
Definition industry.h:265
Owner owner
owner of the industry. Which SHOULD always be (imho) OWNER_NONE
Definition industry.h:116
static Industry * GetByTile(TileIndex tile)
Get the industry of the given tile.
Definition industry.h:251
TileArea location
Location of the industry.
Definition industry.h:106
Station * neutral_station
Associated neutral station.
Definition industry.h:108
~Industry()
Remove any reference to this industry from the game.
StationList stations_near
NOSAVE: List of nearby stations.
Definition industry.h:123
bool IsCargoProduced() const
Test if this industry produces any cargo.
Definition industry.h:229
Owner exclusive_consumer
Which company has exclusive rights to take cargo (INVALID_OWNER = anyone).
Definition industry.h:131
uint16_t counter
used for animation and/or production (if available cargo)
Definition industry.h:113
uint8_t was_cargo_delivered
flag that indicate this has been the closest industry chosen for cargo delivery by a station....
Definition industry.h:119
bool TileBelongsToIndustry(TileIndex tile) const
Check if a given tile belongs to this industry.
Definition industry.h:148
static std::array< FlatSet< IndustryID >, NUM_INDUSTRYTYPES > industries
List of industries of each type.
Definition industry.h:277
static uint SizeX()
Get the size of the map along the X.
Definition map_func.h:262
static TileIndex WrapToMap(TileIndex tile)
'Wraps' the given "tile" so it is within the map.
Definition map_func.h:320
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:331
static uint SizeY()
Get the size of the map along the Y.
Definition map_func.h:271
static uint ScaleByLandProportion(uint n)
Scales the given value by the number of water tiles.
Definition map_func.h:308
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:344
static uint MaxY()
Gets the maximum Y coordinate within the map, including TileType::Void.
Definition map_func.h:298
static uint MaxX()
Gets the maximum X coordinate within the map, including TileType::Void.
Definition map_func.h:289
static uint Size()
Get the size of the map.
Definition map_func.h:280
If you change this, keep in mind that it is also saved in 2 other places:
Definition order_base.h:34
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
static Pool::IterateWrapper< Industry > Iterate(size_t from=0)
static Industry * Get(auto index)
static T * Create(Targs &&... args)
static Industry * GetIfValid(auto index)
static constexpr size_t MAX_SIZE
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.
A location from where cargo can come from (or go to).
Definition source_type.h:32
static Station * Get(auto index)
T * Next() const
Get next vehicle in the chain.
bool HasSpriteGroups() const
Check whether the entity has sprite groups.
Station data structure.
IndustryList industries_near
Cached list of industries near the station that can accept cargo,.
uint16_t subst_id
The id of the entity to replace.
Tile description for the 'land area information' tool.
Definition tile_cmd.h:38
std::optional< std::string > grf
newGRF used for the tile contents
Definition tile_cmd.h:49
StringID str
Description of the tile.
Definition tile_cmd.h:39
std::array< Owner, 4 > owner
Name of the owner(s).
Definition tile_cmd.h:41
uint64_t dparam
Parameter of the str string.
Definition tile_cmd.h:40
Tile information, used while rendering the tile.
Definition tile_cmd.h:32
Slope tileh
Slope of the tile.
Definition tile_cmd.h:33
TileIndex tile
Tile index.
Definition tile_cmd.h:34
Set of callback functions for performing tile operations of a given tile type.
Definition tile_cmd.h:212
uint32_t population
Current population of people.
Definition town.h:53
Town data structure.
Definition town.h:63
TileIndex xy
town center tile
Definition town.h:64
TownCache cache
Container for all cacheable data.
Definition town.h:66
Vehicle data structure.
CargoType cargo_type
type of cargo this vehicle is carrying
bool IsFrontEngine() const
Check if the vehicle is a front engine.
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:94
int GetTileMaxZ(TileIndex t)
Get top height of the tile inside the map.
Definition tile_map.cpp:135
int GetTileZ(TileIndex tile)
Get bottom height of the tile.
Definition tile_map.cpp:115
static bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
static uint TileHeight(Tile tile)
Returns the height of a tile.
Definition tile_map.h:29
int GetTileMaxPixelZ(TileIndex tile)
Get top height of the tile.
Definition tile_map.h:312
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
Slope GetTileSlope(TileIndex tile)
Return the slope of a given tile inside the map.
Definition tile_map.h:279
static TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition tile_map.h:96
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
@ TROPICZONE_RAINFOREST
Rainforest tile.
Definition tile_type.h:84
@ TROPICZONE_DESERT
Tile is desert.
Definition tile_type.h:83
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:100
static constexpr uint TILE_SIZE
Tile size in world coordinates.
Definition tile_type.h:15
@ Station
A tile of a station or airport.
Definition tile_type.h:54
@ Industry
Part of an industry.
Definition tile_type.h:57
@ Void
Invisible tiles at the SW and SE border.
Definition tile_type.h:56
@ Trees
Tile with one or more trees.
Definition tile_type.h:53
@ House
A house by a town.
Definition tile_type.h:52
@ Clear
A tile without any structures, i.e. grass, rocks, farm fields etc.
Definition tile_type.h:49
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
Map accessors for tree tiles.
TreeGrowthStage GetTreeGrowth(Tile t)
Returns the tree growth stage.
Definition tree_map.h:196
TreeGround GetTreeGround(Tile t)
Returns the groundtype for tree tiles.
Definition tree_map.h:102
@ Shore
Shore.
Definition tree_map.h:56
@ Rough
Rough land.
Definition tree_map.h:54
@ Grown
Fully grown tree.
Definition tree_map.h:69
CommandCost EnsureNoVehicleOnGround(TileIndex tile)
Ensure there is no vehicle at the ground at the given position.
Definition vehicle.cpp:556
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 z, const SpriteBounds &bounds, bool transparent, const SubSprite *sub)
Draw a (transparent) sprite at given coordinates with a given bounding box.
Definition viewport.cpp:658
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:820
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)
Tile callback function signature for running periodic tile updates.
bool IsTileOnWater(Tile t)
Tests if the tile was built on water.
Definition water_map.h:138
WaterClass
classes of water (for WaterTileType::Clear water tile type).
Definition water_map.h:39
@ 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:103
WaterClass GetWaterClass(Tile t)
Get the water class at a tile.
Definition water_map.h:114
bool IsWaterTile(Tile t)
Is it a water tile with plain water?
Definition water_map.h:192
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:1209
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:3321
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting).
Definition window.cpp:3199
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: