OpenTTD Source 20251126-master-g67ded4f980
industry_cmd.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10#include "stdafx.h"
11#include "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, MP_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
146Industry::~Industry()
147{
148 if (CleaningPool()) return;
149
150 /* Industry can also be destroyed when not fully initialized.
151 * This means that we do not have to clear tiles either.
152 * Also we must not decrement industry counts in that case. */
153 if (this->location.w == 0) return;
154
155 const bool has_neutral_station = this->neutral_station != nullptr;
156
157 for (TileIndex tile_cur : this->location) {
158 if (IsTileType(tile_cur, MP_INDUSTRY)) {
159 if (GetIndustryIndex(tile_cur) == this->index) {
160 DeleteNewGRFInspectWindow(GSF_INDUSTRYTILES, tile_cur.base());
161
162 /* MakeWaterKeepingClass() can also handle 'land' */
163 MakeWaterKeepingClass(tile_cur, OWNER_NONE);
164 }
165 } else if (IsTileType(tile_cur, MP_STATION) && IsOilRig(tile_cur)) {
166 DeleteOilRig(tile_cur);
167 }
168 }
169
170 if (has_neutral_station) {
171 /* Remove possible docking tiles */
172 for (TileIndex tile_cur : this->location) {
174 }
175 }
176
177 if (GetIndustrySpec(this->type)->behaviour.Test(IndustryBehaviour::PlantFields)) {
178 TileArea ta = TileArea(this->location.tile, 0, 0).Expand(21);
179
180 /* Remove the farmland and convert it to regular tiles over time. */
181 for (TileIndex tile_cur : ta) {
182 if (IsTileType(tile_cur, MP_CLEAR) && IsClearGround(tile_cur, CLEAR_FIELDS) &&
183 GetIndustryIndexOfField(tile_cur) == this->index) {
184 SetIndustryIndexOfField(tile_cur, IndustryID::Invalid());
185 }
186 }
187 }
188
189 /* don't let any disaster vehicle target invalid industry */
191
192 /* Clear the persistent storage. */
193 delete this->psa;
194
196 industries.erase(this->index);
197
201 DeleteNewGRFInspectWindow(GSF_INDUSTRIES, this->index);
202
206
207 for (Station *st : this->stations_near) {
208 st->RemoveIndustryToDeliver(this);
209 }
210}
211
217{
218 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, IDIWD_FORCE_REBUILD);
220}
221
222
228{
229 if (Industry::GetNumItems() == 0) return nullptr;
230 int num = RandomRange((uint16_t)Industry::GetNumItems());
231 size_t index = std::numeric_limits<size_t>::max();
232
233 while (num >= 0) {
234 num--;
235 index++;
236
237 /* Make sure we have a valid industry */
238 while (!Industry::IsValidID(index)) {
239 index++;
240 assert(index < Industry::GetPoolSize());
241 }
242 }
243
244 return Industry::Get(index);
245}
246
247
248static void IndustryDrawSugarMine(const TileInfo *ti)
249{
250 if (!IsIndustryCompleted(ti->tile)) return;
251
252 const DrawIndustryAnimationStruct *d = &_draw_industry_spec1[GetAnimationFrame(ti->tile)];
253
254 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_SIEVE + d->image_1, PAL_NONE, d->x, 0);
255
256 if (d->image_2 != 0) {
257 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_CLOUDS + d->image_2 - 1, PAL_NONE, 8, 41);
258 }
259
260 if (d->image_3 != 0) {
261 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_PILE + d->image_3 - 1, PAL_NONE,
262 _drawtile_proc1[d->image_3 - 1].x, _drawtile_proc1[d->image_3 - 1].y);
263 }
264}
265
266static void IndustryDrawToffeeQuarry(const TileInfo *ti)
267{
268 uint8_t x = 0;
269
270 if (IsIndustryCompleted(ti->tile)) {
271 x = _industry_anim_offs_toffee[GetAnimationFrame(ti->tile)];
272 if (x == 0xFF) {
273 x = 0;
274 }
275 }
276
277 AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_SHOVEL, PAL_NONE, 22 - x, 24 + x);
278 AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_TOFFEE, PAL_NONE, 6, 14);
279}
280
281static void IndustryDrawBubbleGenerator( const TileInfo *ti)
282{
283 if (IsIndustryCompleted(ti->tile)) {
284 AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_BUBBLE, PAL_NONE, 5, _industry_anim_offs_bubbles[GetAnimationFrame(ti->tile)]);
285 }
286 AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_SPRING, PAL_NONE, 3, 67);
287}
288
289static void IndustryDrawToyFactory(const TileInfo *ti)
290{
291 const DrawIndustryAnimationStruct *d = &_industry_anim_offs_toys[GetAnimationFrame(ti->tile)];
292
293 if (d->image_1 != 0xFF) {
294 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_CLAY, PAL_NONE, d->x, 96 + d->image_1);
295 }
296
297 if (d->image_2 != 0xFF) {
298 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_ROBOT, PAL_NONE, 16 - d->image_2 * 2, 100 + d->image_2);
299 }
300
301 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP, PAL_NONE, 7, d->image_3);
302 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP_HOLDER, PAL_NONE, 0, 42);
303}
304
305static void IndustryDrawCoalPlantSparks(const TileInfo *ti)
306{
307 if (IsIndustryCompleted(ti->tile)) {
308 uint8_t image = GetAnimationFrame(ti->tile);
309
310 if (image != 0 && image < 7) {
311 AddChildSpriteScreen(image + SPR_IT_POWER_PLANT_TRANSFORMERS,
312 PAL_NONE,
313 _coal_plant_sparks[image - 1].x,
314 _coal_plant_sparks[image - 1].y
315 );
316 }
317 }
318}
319
320typedef void IndustryDrawTileProc(const TileInfo *ti);
321static IndustryDrawTileProc * const _industry_draw_tile_procs[5] = {
322 IndustryDrawSugarMine,
323 IndustryDrawToffeeQuarry,
324 IndustryDrawBubbleGenerator,
325 IndustryDrawToyFactory,
326 IndustryDrawCoalPlantSparks,
327};
328
329static void DrawTile_Industry(TileInfo *ti)
330{
331 IndustryGfx gfx = GetIndustryGfx(ti->tile);
333 const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
334
335 /* Retrieve pointer to the draw industry tile struct */
336 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
337 /* Draw the tile using the specialized method of newgrf industrytile.
338 * DrawNewIndustry will return false if ever the resolver could not
339 * find any sprite to display. So in this case, we will jump on the
340 * substitute gfx instead. */
341 if (indts->grf_prop.HasSpriteGroups() && DrawNewIndustryTile(ti, ind, gfx, indts)) {
342 return;
343 } else {
344 /* No sprite group (or no valid one) found, meaning no graphics associated.
345 * Use the substitute one instead */
346 if (indts->grf_prop.subst_id != INVALID_INDUSTRYTILE) {
347 gfx = indts->grf_prop.subst_id;
348 /* And point the industrytile spec accordingly */
349 indts = GetIndustryTileSpec(gfx);
350 }
351 }
352 }
353
354 const DrawBuildingsTileStruct *dits = &_industry_draw_tile_data[gfx << 2 | (indts->anim_state ?
357
358 SpriteID image = dits->ground.sprite;
359
360 /* DrawFoundation() modifies ti->z and ti->tileh */
362
363 /* If the ground sprite is the default flat water sprite, draw also canal/river borders.
364 * Do not do this if the tile's WaterClass is 'land'. */
365 if (image == SPR_FLAT_WATER_TILE && IsTileOnWater(ti->tile)) {
366 DrawWaterClassGround(ti);
367 } else {
369 }
370
371 /* If industries are transparent and invisible, do not draw the upper part */
372 if (IsInvisibilitySet(TO_INDUSTRIES)) return;
373
374 /* Add industry on top of the ground? */
375 image = dits->building.sprite;
376 if (image != 0) {
378 *ti, *dits, IsTransparencySet(TO_INDUSTRIES));
379
380 if (IsTransparencySet(TO_INDUSTRIES)) return;
381 }
382
383 {
384 int proc = dits->draw_proc - 1;
385 if (proc >= 0) _industry_draw_tile_procs[proc](ti);
386 }
387}
388
389static int GetSlopePixelZ_Industry(TileIndex tile, uint, uint, bool)
390{
391 return GetTileMaxPixelZ(tile);
392}
393
394static Foundation GetFoundation_Industry(TileIndex tile, Slope tileh)
395{
396 IndustryGfx gfx = GetIndustryGfx(tile);
397
398 /* For NewGRF industry tiles we might not be drawing a foundation. We need to
399 * account for this, as other structures should
400 * draw the wall of the foundation in this case.
401 */
402 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
403 const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
405 uint32_t callback_res = GetIndustryTileCallback(CBID_INDTILE_DRAW_FOUNDATIONS, 0, 0, gfx, Industry::GetByTile(tile), tile);
406 if (callback_res != CALLBACK_FAILED && !ConvertBooleanCallback(indts->grf_prop.grffile, CBID_INDTILE_DRAW_FOUNDATIONS, callback_res)) return FOUNDATION_NONE;
407 }
408 }
409 return FlatteningFoundation(tileh);
410}
411
412static void AddAcceptedCargo_Industry(TileIndex tile, CargoArray &acceptance, CargoTypes &always_accepted)
413{
414 IndustryGfx gfx = GetIndustryGfx(tile);
415 const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
416 const Industry *ind = Industry::GetByTile(tile);
417
418 /* Starting point for acceptance */
419 auto accepts_cargo = itspec->accepts_cargo;
420 auto cargo_acceptance = itspec->acceptance;
421
423 /* Copy all accepted cargoes from industry itself */
424 for (const auto &a : ind->accepted) {
425 auto pos = std::ranges::find(accepts_cargo, a.cargo);
426 if (pos == std::end(accepts_cargo)) {
427 /* Not found, insert */
428 pos = std::ranges::find(accepts_cargo, INVALID_CARGO);
429 if (pos == std::end(accepts_cargo)) continue; // nowhere to place, give up on this one
430 *pos = a.cargo;
431 }
432 cargo_acceptance[std::distance(std::begin(accepts_cargo), pos)] += 8;
433 }
434 }
435
437 /* Try callback for accepts list, if success override all existing accepts */
438 uint16_t res = GetIndustryTileCallback(CBID_INDTILE_ACCEPT_CARGO, 0, 0, gfx, Industry::GetByTile(tile), tile);
439 if (res != CALLBACK_FAILED) {
440 accepts_cargo.fill(INVALID_CARGO);
441 for (uint i = 0; i < INDUSTRY_ORIGINAL_NUM_INPUTS; i++) accepts_cargo[i] = GetCargoTranslation(GB(res, i * 5, 5), itspec->grf_prop.grffile);
442 }
443 }
444
446 /* Try callback for acceptance list, if success override all existing acceptance */
447 uint16_t res = GetIndustryTileCallback(CBID_INDTILE_CARGO_ACCEPTANCE, 0, 0, gfx, Industry::GetByTile(tile), tile);
448 if (res != CALLBACK_FAILED) {
449 cargo_acceptance.fill(0);
450 for (uint i = 0; i < INDUSTRY_ORIGINAL_NUM_INPUTS; i++) cargo_acceptance[i] = GB(res, i * 4, 4);
451 }
452 }
453
454 for (size_t i = 0; i < std::size(itspec->accepts_cargo); i++) {
455 CargoType cargo = accepts_cargo[i];
456 if (!IsValidCargoType(cargo) || cargo_acceptance[i] <= 0) continue; // work only with valid cargoes
457
458 /* Add accepted cargo */
459 acceptance[cargo] += cargo_acceptance[i];
460
461 /* Maybe set 'always accepted' bit (if it's not set already) */
462 if (HasBit(always_accepted, cargo)) continue;
463
464 /* Test whether the industry itself accepts the cargo type */
465 if (ind->IsCargoAccepted(cargo)) continue;
466
467 /* If the industry itself doesn't accept this cargo, set 'always accepted' bit */
468 SetBit(always_accepted, cargo);
469 }
470}
471
472static void GetTileDesc_Industry(TileIndex tile, TileDesc &td)
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
489static CommandCost ClearTile_Industry(TileIndex tile, DoCommandFlags flags)
490{
491 Industry *i = Industry::GetByTile(tile);
492 const IndustrySpec *indspec = GetIndustrySpec(i->type);
493
494 /* water can destroy industries
495 * in editor you can bulldoze industries
496 * with magic_bulldozer cheat you can destroy industries
497 * (area around OILRIG is water, so water shouldn't flood it
498 */
499 if ((_current_company != OWNER_WATER && _game_mode != GM_EDITOR &&
501 flags.Test(DoCommandFlag::Auto) ||
504 HasBit(GetIndustryTileSpec(GetIndustryGfx(tile))->slopes_refused, 5)))) {
505
506 if (flags.Test(DoCommandFlag::Auto)) {
507 return CommandCostWithParam(STR_ERROR_GENERIC_OBJECT_IN_THE_WAY, indspec->name);
508 }
510 }
511
512 if (flags.Test(DoCommandFlag::Execute)) {
513 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index));
514 Game::NewEvent(new ScriptEventIndustryClose(i->index));
515 delete i;
516 }
518}
519
526{
527 Industry *i = Industry::GetByTile(tile);
528 const IndustrySpec *indspec = GetIndustrySpec(i->type);
529 bool moved_cargo = false;
530
531 for (auto &p : i->produced) {
532 uint cw = ClampTo<uint8_t>(p.waiting);
533 if (cw > indspec->minimal_cargo && IsValidCargoType(p.cargo)) {
534 p.waiting -= cw;
535
536 /* fluctuating economy? */
537 if (EconomyIsInRecession()) cw = (cw + 1) / 2;
538
539 p.history[THIS_MONTH].production += cw;
540
541 uint am = MoveGoodsToStation(p.cargo, cw, {i->index, SourceType::Industry}, i->stations_near, i->exclusive_consumer);
542 p.history[THIS_MONTH].transported += am;
543
544 moved_cargo |= (am != 0);
545 }
546 }
547
548 return moved_cargo;
549}
550
551static void AnimateSugarSieve(TileIndex tile)
552{
553 uint8_t m = GetAnimationFrame(tile) + 1;
554
556 switch (m & 7) {
557 case 2: SndPlayTileFx(SND_2D_SUGAR_MINE_1, tile); break;
558 case 6: SndPlayTileFx(SND_29_SUGAR_MINE_2, tile); break;
559 }
560 }
561
562 if (m >= 96) {
563 m = 0;
564 DeleteAnimatedTile(tile);
565 }
566 SetAnimationFrame(tile, m);
567
569}
570
571static void AnimateToffeeQuarry(TileIndex tile)
572{
573 uint8_t m = GetAnimationFrame(tile);
574
575 if (_industry_anim_offs_toffee[m] == 0xFF && _settings_client.sound.ambient) {
576 SndPlayTileFx(SND_30_TOFFEE_QUARRY, tile);
577 }
578
579 if (++m >= 70) {
580 m = 0;
581 DeleteAnimatedTile(tile);
582 }
583 SetAnimationFrame(tile, m);
584
586}
587
588static void AnimateBubbleCatcher(TileIndex tile)
589{
590 uint8_t m = GetAnimationFrame(tile);
591
592 if (++m >= 40) {
593 m = 0;
594 DeleteAnimatedTile(tile);
595 }
596 SetAnimationFrame(tile, m);
597
599}
600
601static void AnimatePowerPlantSparks(TileIndex tile)
602{
603 uint8_t m = GetAnimationFrame(tile);
604 if (m == 6) {
605 SetAnimationFrame(tile, 0);
606 DeleteAnimatedTile(tile);
607 } else {
608 SetAnimationFrame(tile, m + 1);
609 }
611}
612
613static void AnimateToyFactory(TileIndex tile)
614{
615 uint8_t m = GetAnimationFrame(tile) + 1;
616
617 switch (m) {
618 case 1: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2C_TOY_FACTORY_1, tile); break;
619 case 23: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2B_TOY_FACTORY_2, tile); break;
620 case 28: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2A_TOY_FACTORY_3, tile); break;
621 default:
622 if (m >= 50) {
623 int n = GetIndustryAnimationLoop(tile) + 1;
624 m = 0;
625 if (n >= 8) {
626 n = 0;
627 DeleteAnimatedTile(tile);
628 }
630 }
631 }
632
633 SetAnimationFrame(tile, m);
635}
636
637static void AnimatePlasticFountain(TileIndex tile, IndustryGfx gfx)
638{
639 gfx = (gfx < GFX_PLASTIC_FOUNTAIN_ANIMATED_8) ? gfx + 1 : GFX_PLASTIC_FOUNTAIN_ANIMATED_1;
640 SetIndustryGfx(tile, gfx);
642}
643
644static void AnimateOilWell(TileIndex tile, IndustryGfx gfx)
645{
646 bool b = Chance16(1, 7);
647 uint8_t m = GetAnimationFrame(tile) + 1;
648 if (m == 4 && (m = 0, ++gfx) == GFX_OILWELL_ANIMATED_3 + 1 && (gfx = GFX_OILWELL_ANIMATED_1, b)) {
649 SetIndustryGfx(tile, GFX_OILWELL_NOT_ANIMATED);
651 DeleteAnimatedTile(tile);
652 } else {
653 SetAnimationFrame(tile, m);
654 SetIndustryGfx(tile, gfx);
655 }
657}
658
659static void AnimateMineTower(TileIndex tile)
660{
661 int state = TimerGameTick::counter & 0x7FF;
662
663 if ((state -= 0x400) < 0) return;
664
665 if (state < 0x1A0) {
666 if (state < 0x20 || state >= 0x180) {
667 uint8_t m = GetAnimationFrame(tile);
668 if (!(m & 0x40)) {
669 SetAnimationFrame(tile, m | 0x40);
670 if (_settings_client.sound.ambient) SndPlayTileFx(SND_0B_MINE, tile);
671 }
672 if (state & 7) return;
673 } else {
674 if (state & 3) return;
675 }
676 uint8_t m = (GetAnimationFrame(tile) + 1) | 0x40;
677 if (m > 0xC2) m = 0xC0;
678 SetAnimationFrame(tile, m);
680 } else if (state >= 0x200 && state < 0x3A0) {
681 int i = (state < 0x220 || state >= 0x380) ? 7 : 3;
682 if (state & i) return;
683
684 uint8_t m = (GetAnimationFrame(tile) & 0xBF) - 1;
685 if (m < 0x80) m = 0x82;
686 SetAnimationFrame(tile, m);
688 }
689}
690
691static void AnimateTile_Industry(TileIndex tile)
692{
693 IndustryGfx gfx = GetIndustryGfx(tile);
694
695 if (GetIndustryTileSpec(gfx)->animation.status != AnimationStatus::NoAnimation) {
696 AnimateNewIndustryTile(tile);
697 return;
698 }
699
700 switch (gfx) {
701 case GFX_SUGAR_MINE_SIEVE:
702 if ((TimerGameTick::counter & 1) == 0) AnimateSugarSieve(tile);
703 break;
704
705 case GFX_TOFFEE_QUARRY:
706 if ((TimerGameTick::counter & 3) == 0) AnimateToffeeQuarry(tile);
707 break;
708
709 case GFX_BUBBLE_CATCHER:
710 if ((TimerGameTick::counter & 1) == 0) AnimateBubbleCatcher(tile);
711 break;
712
713 case GFX_POWERPLANT_SPARKS:
714 if ((TimerGameTick::counter & 3) == 0) AnimatePowerPlantSparks(tile);
715 break;
716
717 case GFX_TOY_FACTORY:
718 if ((TimerGameTick::counter & 1) == 0) AnimateToyFactory(tile);
719 break;
720
721 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
722 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
723 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
724 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
725 if ((TimerGameTick::counter & 3) == 0) AnimatePlasticFountain(tile, gfx);
726 break;
727
728 case GFX_OILWELL_ANIMATED_1:
729 case GFX_OILWELL_ANIMATED_2:
730 case GFX_OILWELL_ANIMATED_3:
731 if ((TimerGameTick::counter & 7) == 0) AnimateOilWell(tile, gfx);
732 break;
733
734 case GFX_COAL_MINE_TOWER_ANIMATED:
735 case GFX_COPPER_MINE_TOWER_ANIMATED:
736 case GFX_GOLD_MINE_TOWER_ANIMATED:
737 AnimateMineTower(tile);
738 break;
739 }
740}
741
742static void CreateChimneySmoke(TileIndex tile)
743{
744 uint x = TileX(tile) * TILE_SIZE;
745 uint y = TileY(tile) * TILE_SIZE;
746 int z = GetTileMaxPixelZ(tile);
747
748 CreateEffectVehicle(x + 15, y + 14, z + 59, EV_CHIMNEY_SMOKE);
749}
750
751static void MakeIndustryTileBigger(TileIndex tile)
752{
753 uint8_t cnt = GetIndustryConstructionCounter(tile) + 1;
754 if (cnt != 4) {
756 return;
757 }
758
759 uint8_t stage = GetIndustryConstructionStage(tile) + 1;
761 SetIndustryConstructionStage(tile, stage);
762 TriggerIndustryTileAnimation_ConstructionStageChanged(tile, false);
763 if (stage == INDUSTRY_COMPLETED) SetIndustryCompleted(tile);
764
766
767 if (!IsIndustryCompleted(tile)) return;
768
769 IndustryGfx gfx = GetIndustryGfx(tile);
770 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
771 /* New industries are already animated on construction. */
772 return;
773 }
774
775 switch (gfx) {
776 case GFX_POWERPLANT_CHIMNEY:
777 CreateChimneySmoke(tile);
778 break;
779
780 case GFX_OILRIG_1: {
781 /* Do not require an industry tile to be after the first two GFX_OILRIG_1
782 * tiles (like the default oil rig). Do a proper check to ensure the
783 * tiles belong to the same industry and based on that build the oil rig's
784 * station. */
785 TileIndex other = tile + TileDiffXY(0, 1);
786
787 if (IsTileType(other, MP_INDUSTRY) &&
788 GetIndustryGfx(other) == GFX_OILRIG_1 &&
789 GetIndustryIndex(tile) == GetIndustryIndex(other)) {
790 BuildOilRig(tile);
791 }
792 break;
793 }
794
795 case GFX_TOY_FACTORY:
796 case GFX_BUBBLE_CATCHER:
797 case GFX_TOFFEE_QUARRY:
798 SetAnimationFrame(tile, 0);
800 break;
801
802 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
803 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
804 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
805 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
806 AddAnimatedTile(tile, false);
807 break;
808 }
809}
810
811static void TileLoopIndustry_BubbleGenerator(TileIndex tile)
812{
813 static const int8_t _bubble_spawn_location[3][4] = {
814 { 11, 0, -4, -14 },
815 { -4, -10, -4, 1 },
816 { 49, 59, 60, 65 },
817 };
818
819 if (_settings_client.sound.ambient) SndPlayTileFx(SND_2E_BUBBLE_GENERATOR, tile);
820
821 int dir = Random() & 3;
822
824 TileX(tile) * TILE_SIZE + _bubble_spawn_location[0][dir],
825 TileY(tile) * TILE_SIZE + _bubble_spawn_location[1][dir],
826 _bubble_spawn_location[2][dir],
828 );
829
830 if (v != nullptr) v->animation_substate = dir;
831}
832
833static void TileLoop_Industry(TileIndex tile)
834{
835 if (IsTileOnWater(tile)) TileLoop_Water(tile);
836
837 /* Normally this doesn't happen, but if an industry NewGRF is removed
838 * an industry that was previously build on water can now be flooded.
839 * If this happens the tile is no longer an industry tile after
840 * returning from TileLoop_Water. */
841 if (!IsTileType(tile, MP_INDUSTRY)) return;
842
844
845 if (!IsIndustryCompleted(tile)) {
846 MakeIndustryTileBigger(tile);
847 return;
848 }
849
850 if (_game_mode == GM_EDITOR) return;
851
852 if (TransportIndustryGoods(tile) && !TriggerIndustryAnimation(Industry::GetByTile(tile), IndustryAnimationTrigger::CargoDistributed)) {
854
855 if (newgfx != INDUSTRYTILE_NOANIM) {
858 SetIndustryGfx(tile, newgfx);
860 return;
861 }
862 }
863
864 if (TriggerIndustryTileAnimation(tile, IndustryAnimationTrigger::TileLoop)) return;
865
866 IndustryGfx newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_next;
867 if (newgfx != INDUSTRYTILE_NOANIM) {
869 SetIndustryGfx(tile, newgfx);
871 return;
872 }
873
874 IndustryGfx gfx = GetIndustryGfx(tile);
875 switch (gfx) {
876 case GFX_COAL_MINE_TOWER_NOT_ANIMATED:
877 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED:
878 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED:
879 if (!(TimerGameTick::counter & 0x400) && Chance16(1, 2)) {
880 switch (gfx) {
881 case GFX_COAL_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COAL_MINE_TOWER_ANIMATED; break;
882 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_ANIMATED; break;
883 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_ANIMATED; break;
884 }
885 SetIndustryGfx(tile, gfx);
886 SetAnimationFrame(tile, 0x80);
887 AddAnimatedTile(tile);
888 }
889 break;
890
891 case GFX_OILWELL_NOT_ANIMATED:
892 if (Chance16(1, 6)) {
893 SetIndustryGfx(tile, GFX_OILWELL_ANIMATED_1);
894 SetAnimationFrame(tile, 0);
895 AddAnimatedTile(tile);
896 }
897 break;
898
899 case GFX_COAL_MINE_TOWER_ANIMATED:
900 case GFX_COPPER_MINE_TOWER_ANIMATED:
901 case GFX_GOLD_MINE_TOWER_ANIMATED:
902 if (!(TimerGameTick::counter & 0x400)) {
903 switch (gfx) {
904 case GFX_COAL_MINE_TOWER_ANIMATED: gfx = GFX_COAL_MINE_TOWER_NOT_ANIMATED; break;
905 case GFX_COPPER_MINE_TOWER_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_NOT_ANIMATED; break;
906 case GFX_GOLD_MINE_TOWER_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_NOT_ANIMATED; break;
907 }
908 SetIndustryGfx(tile, gfx);
911 DeleteAnimatedTile(tile);
913 }
914 break;
915
916 case GFX_POWERPLANT_SPARKS:
917 if (Chance16(1, 3)) {
918 if (_settings_client.sound.ambient) SndPlayTileFx(SND_0C_POWER_STATION, tile);
919 AddAnimatedTile(tile);
920 }
921 break;
922
923 case GFX_COPPER_MINE_CHIMNEY:
925 break;
926
927
928 case GFX_TOY_FACTORY: {
929 Industry *i = Industry::GetByTile(tile);
930 if (i->was_cargo_delivered) {
931 i->was_cargo_delivered = false;
933 AddAnimatedTile(tile);
934 }
935 }
936 break;
937
938 case GFX_BUBBLE_GENERATOR:
939 TileLoopIndustry_BubbleGenerator(tile);
940 break;
941
942 case GFX_TOFFEE_QUARRY:
943 AddAnimatedTile(tile);
944 break;
945
946 case GFX_SUGAR_MINE_SIEVE:
947 if (Chance16(1, 3)) AddAnimatedTile(tile);
948 break;
949 }
950}
951
952static bool ClickTile_Industry(TileIndex tile)
953{
954 ShowIndustryViewWindow(GetIndustryIndex(tile));
955 return true;
956}
957
958static TrackStatus GetTileTrackStatus_Industry(TileIndex, TransportType, uint, DiagDirection)
959{
960 return 0;
961}
962
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, MP_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)
1002{
1003 switch (GetTileType(tile)) {
1004 case MP_CLEAR: return !IsSnowTile(tile) && !IsClearGround(tile, CLEAR_DESERT) && (allow_fields || !IsClearGround(tile, CLEAR_FIELDS));
1005 case MP_TREES: return GetTreeGround(tile) != TREE_GROUND_SHORE;
1006 default: return false;
1007 }
1008}
1009
1017static void SetupFarmFieldFence(TileIndex tile, int size, uint8_t type, DiagDirection side)
1018{
1020 TileIndexDiff neighbour_diff = TileOffsByDiagDir(side);
1021
1022 do {
1023 tile = Map::WrapToMap(tile);
1024
1025 if (IsTileType(tile, MP_CLEAR) && IsClearGround(tile, CLEAR_FIELDS)) {
1026 TileIndex neighbour = tile + neighbour_diff;
1027 if (!IsTileType(neighbour, MP_CLEAR) || !IsClearGround(neighbour, CLEAR_FIELDS) || GetFence(neighbour, ReverseDiagDir(side)) == 0) {
1028 /* Add fence as long as neighbouring tile does not already have a fence in the same position. */
1029 uint8_t or_ = type;
1030
1031 if (or_ == 1 && Chance16(1, 7)) or_ = 2;
1032
1033 SetFence(tile, side, or_);
1034 }
1035 }
1036
1037 tile += diff;
1038 } while (--size);
1039}
1040
1041static void PlantFarmField(TileIndex tile, IndustryID industry)
1042{
1043 if (_settings_game.game_creation.landscape == LandscapeType::Arctic) {
1044 if (GetTileZ(tile) + 2 >= GetSnowLine()) return;
1045 }
1046
1047 /* determine field size */
1048 uint32_t r = (Random() & 0x303) + 0x404;
1049 if (_settings_game.game_creation.landscape == LandscapeType::Arctic) r += 0x404;
1050 uint size_x = GB(r, 0, 8);
1051 uint size_y = GB(r, 8, 8);
1052
1053 TileArea ta(tile - TileDiffXY(std::min(TileX(tile), size_x / 2), std::min(TileY(tile), size_y / 2)), size_x, size_y);
1054 ta.ClampToMap();
1055
1056 if (ta.w == 0 || ta.h == 0) return;
1057
1058 /* check the amount of bad tiles */
1059 int count = 0;
1060 for (TileIndex cur_tile : ta) {
1061 assert(cur_tile < Map::Size());
1062 count += IsSuitableForFarmField(cur_tile, false);
1063 }
1064 if (count * 2 < ta.w * ta.h) return;
1065
1066 /* determine type of field */
1067 r = Random();
1068 uint counter = GB(r, 5, 3);
1069 uint field_type = GB(r, 8, 8) * 9 >> 8;
1070
1071 /* make field */
1072 for (TileIndex cur_tile : ta) {
1073 assert(cur_tile < Map::Size());
1074 if (IsSuitableForFarmField(cur_tile, true)) {
1075 MakeField(cur_tile, field_type, industry);
1076 SetClearCounter(cur_tile, counter);
1077 MarkTileDirtyByTile(cur_tile);
1078 }
1079 }
1080
1081 int type = 3;
1082 if (_settings_game.game_creation.landscape != LandscapeType::Arctic && _settings_game.game_creation.landscape != LandscapeType::Tropic) {
1083 type = _plantfarmfield_type[Random() & 0xF];
1084 }
1085
1086 SetupFarmFieldFence(ta.tile, ta.h, type, DIAGDIR_NE);
1087 SetupFarmFieldFence(ta.tile, ta.w, type, DIAGDIR_NW);
1088 SetupFarmFieldFence(ta.tile + TileDiffXY(ta.w - 1, 0), ta.h, type, DIAGDIR_SW);
1089 SetupFarmFieldFence(ta.tile + TileDiffXY(0, ta.h - 1), ta.w, type, DIAGDIR_SE);
1090}
1091
1092void PlantRandomFarmField(const Industry *i)
1093{
1094 int x = i->location.w / 2 + Random() % 31 - 16;
1095 int y = i->location.h / 2 + Random() % 31 - 16;
1096
1097 TileIndex tile = TileAddWrap(i->location.tile, x, y);
1098
1099 if (tile != INVALID_TILE) PlantFarmField(tile, i->index);
1100}
1101
1107{
1108 /* Don't process lumber mill if cargo is not set up correctly. */
1109 auto itp = std::begin(i->produced);
1110 if (itp == std::end(i->produced) || !IsValidCargoType(itp->cargo)) return;
1111
1112 /* We only want to cut trees if all tiles are completed. */
1113 for (TileIndex tile_cur : i->location) {
1114 if (i->TileBelongsToIndustry(tile_cur)) {
1115 if (!IsIndustryCompleted(tile_cur)) return;
1116 }
1117 }
1118
1119 for (auto tile : SpiralTileSequence(i->location.tile, 40)) { // 40x40 tiles to search.
1120 if (!IsTileType(tile, MP_TREES) || GetTreeGrowth(tile) < TreeGrowthStage::Grown) continue;
1121
1122 /* found a tree */
1123 _industry_sound_ctr = 1;
1124 _industry_sound_tile = tile;
1125 if (_settings_client.sound.ambient) SndPlayTileFx(SND_38_LUMBER_MILL_1, tile);
1126
1129
1130 /* Add according value to waiting cargo. */
1131 itp->waiting = ClampTo<uint16_t>(itp->waiting + ScaleByCargoScale(45, false));
1132 break;
1133 }
1134}
1135
1141static void ProduceIndustryGoodsHelper(Industry *i, bool scale)
1142{
1143 for (auto &p : i->produced) {
1144 if (!IsValidCargoType(p.cargo)) continue;
1145
1146 uint16_t amount = p.rate;
1147 if (scale) amount = ScaleByCargoScale(amount, false);
1148
1149 p.waiting = ClampTo<uint16_t>(p.waiting + amount);
1150 }
1151}
1152
1153static void ProduceIndustryGoods(Industry *i)
1154{
1155 const IndustrySpec *indsp = GetIndustrySpec(i->type);
1156
1157 /* play a sound? */
1158 if ((i->counter & 0x3F) == 0) {
1159 uint32_t r;
1160 if (Chance16R(1, 14, r) && !indsp->random_sounds.empty() && _settings_client.sound.ambient) {
1161 if (std::any_of(std::begin(i->produced), std::end(i->produced), [](const auto &p) { return p.history[LAST_MONTH].production > 0; })) {
1162 /* Play sound since last month had production */
1163 SndPlayTileFx(
1164 static_cast<SoundFx>(indsp->random_sounds[((r >> 16) * indsp->random_sounds.size()) >> 16]),
1165 i->location.tile);
1166 }
1167 }
1168 }
1169
1170 i->counter--;
1171
1172 /* If using an industry callback, scale the callback interval by cargo scale percentage. */
1177 }
1178 }
1179
1180 /*
1181 * All other production and special effects happen every 256 ticks, and cargo production is just scaled by the cargo scale percentage.
1182 * 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.
1183 */
1184 if ((i->counter % Ticks::INDUSTRY_PRODUCE_TICKS) == 0) {
1185 /* Handle non-callback cargo production. */
1187
1188 IndustryBehaviours indbehav = indsp->behaviour;
1189
1190 if (indbehav.Test(IndustryBehaviour::PlantFields)) {
1191 uint16_t cb_res = CALLBACK_FAILED;
1194 }
1195
1196 bool plant;
1197 if (cb_res != CALLBACK_FAILED) {
1199 } else {
1200 plant = Chance16(1, 8);
1201 }
1202
1203 if (plant) PlantRandomFarmField(i);
1204 }
1205 if (indbehav.Test(IndustryBehaviour::CutTrees)) {
1206 uint16_t cb_res = CALLBACK_FAILED;
1209 }
1210
1211 bool cut;
1212 if (cb_res != CALLBACK_FAILED) {
1214 } else {
1215 cut = ((i->counter % Ticks::INDUSTRY_CUT_TREE_TICKS) == 0);
1216 }
1217
1218 if (cut) ChopLumberMillTrees(i);
1219 }
1220
1222 TriggerIndustryAnimation(i, IndustryAnimationTrigger::IndustryTick);
1223 }
1224}
1225
1226void OnTick_Industry()
1227{
1228 if (_industry_sound_ctr != 0) {
1229 _industry_sound_ctr++;
1230
1231 if (_industry_sound_ctr == 75) {
1232 if (_settings_client.sound.ambient) SndPlayTileFx(SND_37_LUMBER_MILL_2, _industry_sound_tile);
1233 } else if (_industry_sound_ctr == 160) {
1234 _industry_sound_ctr = 0;
1235 if (_settings_client.sound.ambient) SndPlayTileFx(SND_36_LUMBER_MILL_3, _industry_sound_tile);
1236 }
1237 }
1238
1239 if (_game_mode == GM_EDITOR) return;
1240
1241 for (Industry *i : Industry::Iterate()) {
1242 ProduceIndustryGoods(i);
1243
1244 if ((TimerGameTick::counter + i->index) % Ticks::DAY_TICKS == 0) {
1245 for (auto &a : i->accepted) a.accumulated_waiting += a.waiting;
1246 }
1247 }
1248}
1249
1255{
1256 return CommandCost();
1257}
1258
1265{
1266 if (_settings_game.game_creation.landscape == LandscapeType::Arctic) {
1267 if (GetTileZ(tile) < HighestSnowLine() + 2) {
1268 return CommandCost(STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED);
1269 }
1270 }
1271 return CommandCost();
1272}
1273
1281static bool CheckScaledDistanceFromEdge(TileIndex tile, uint maxdist)
1282{
1283 uint maxdist_x = maxdist;
1284 uint maxdist_y = maxdist;
1285
1286 if (Map::SizeX() > 256) maxdist_x *= Map::SizeX() / 256;
1287 if (Map::SizeY() > 256) maxdist_y *= Map::SizeY() / 256;
1288
1289 if (DistanceFromEdgeDir(tile, DIAGDIR_NE) < maxdist_x) return true;
1290 if (DistanceFromEdgeDir(tile, DIAGDIR_NW) < maxdist_y) return true;
1291 if (DistanceFromEdgeDir(tile, DIAGDIR_SW) < maxdist_x) return true;
1292 if (DistanceFromEdgeDir(tile, DIAGDIR_SE) < maxdist_y) return true;
1293
1294 return false;
1295}
1296
1303{
1304 if (_game_mode == GM_EDITOR) return CommandCost();
1305
1307
1308 return CommandCost(STR_ERROR_CAN_ONLY_BE_POSITIONED);
1309}
1310
1311extern bool _ignore_industry_restrictions;
1312
1319{
1320 if (_game_mode == GM_EDITOR && _ignore_industry_restrictions) return CommandCost();
1321
1322 if (TileHeight(tile) == 0 &&
1324
1325 return CommandCost(STR_ERROR_CAN_ONLY_BE_POSITIONED);
1326}
1327
1334{
1335 if (_settings_game.game_creation.landscape == LandscapeType::Arctic) {
1336 if (GetTileZ(tile) + 2 >= HighestSnowLine()) {
1337 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1338 }
1339 }
1340 return CommandCost();
1341}
1342
1349{
1350 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
1351 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1352 }
1353 return CommandCost();
1354}
1355
1362{
1363 if (GetTropicZone(tile) != TROPICZONE_DESERT) {
1364 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT);
1365 }
1366 return CommandCost();
1367}
1368
1375{
1376 if (GetTropicZone(tile) != TROPICZONE_RAINFOREST) {
1377 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST);
1378 }
1379 return CommandCost();
1380}
1381
1388{
1389 if (GetTileZ(tile) > 4) {
1390 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS);
1391 }
1392 return CommandCost();
1393}
1394
1401
1414
1425static CommandCost FindTownForIndustry(TileIndex tile, IndustryType type, Town **t)
1426{
1427 *t = ClosestTownFromTile(tile, UINT_MAX);
1428
1430
1431 for (const IndustryID &industry : Industry::industries[type]) {
1432 if (Industry::Get(industry)->town == *t) {
1433 *t = nullptr;
1434 return CommandCost(STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN);
1435 }
1436 }
1437
1438 return CommandCost();
1439}
1440
1441bool IsSlopeRefused(Slope current, Slope refused)
1442{
1443 if (IsSteepSlope(current)) return true;
1444 if (current != SLOPE_FLAT) {
1445 if (IsSteepSlope(refused)) return true;
1446
1447 Slope t = ComplementSlope(current);
1448
1449 if ((refused & SLOPE_W) && (t & SLOPE_NW)) return true;
1450 if ((refused & SLOPE_S) && (t & SLOPE_NE)) return true;
1451 if ((refused & SLOPE_E) && (t & SLOPE_SW)) return true;
1452 if ((refused & SLOPE_N) && (t & SLOPE_SE)) return true;
1453 }
1454
1455 return false;
1456}
1457
1465static CommandCost CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTileLayout &layout, IndustryType type)
1466{
1467 IndustryBehaviours ind_behav = GetIndustrySpec(type)->behaviour;
1468
1469 for (const IndustryTileLayoutTile &it : layout) {
1470 IndustryGfx gfx = GetTranslatedIndustryTileID(it.gfx);
1471 TileIndex cur_tile = TileAddWrap(tile, it.ti.x, it.ti.y);
1472
1473 if (!IsValidTile(cur_tile)) {
1474 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1475 }
1476
1477 if (gfx == GFX_WATERTILE_SPECIALCHECK) {
1478 if (!IsWaterTile(cur_tile) ||
1479 !IsTileFlat(cur_tile)) {
1480 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1481 }
1482 } else {
1483 CommandCost ret = EnsureNoVehicleOnGround(cur_tile);
1484 if (ret.Failed()) return ret;
1485 if (IsBridgeAbove(cur_tile)) return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1486
1487 const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
1488
1489 /* Perform land/water check if not disabled */
1490 if (!HasBit(its->slopes_refused, 5) && ((HasTileWaterClass(cur_tile) && IsTileOnWater(cur_tile)) != ind_behav.Test(IndustryBehaviour::BuiltOnWater))) return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1491
1492 if (ind_behav.Any({IndustryBehaviour::OnlyInTown, IndustryBehaviour::Town1200More}) || // Tile must be a house
1493 (ind_behav.Test(IndustryBehaviour::OnlyNearTown) && IsTileType(cur_tile, MP_HOUSE))) { // Tile is allowed to be a house (and it is a house)
1494 if (!IsTileType(cur_tile, MP_HOUSE)) {
1495 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS);
1496 }
1497
1498 /* Clear the tiles as OWNER_TOWN to not affect town rating, and to not clear protected buildings */
1500 ret = Command<CMD_LANDSCAPE_CLEAR>::Do({}, cur_tile);
1501 cur_company.Restore();
1502
1503 if (ret.Failed()) return ret;
1504 } else {
1505 /* Clear the tiles, but do not affect town ratings */
1507 if (ret.Failed()) return ret;
1508 }
1509 }
1510 }
1511
1512 return CommandCost();
1513}
1514
1527static 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)
1528{
1529 bool refused_slope = false;
1530 bool custom_shape = false;
1531
1532 for (const IndustryTileLayoutTile &it : layout) {
1533 IndustryGfx gfx = GetTranslatedIndustryTileID(it.gfx);
1534 TileIndex cur_tile = TileAddWrap(tile, it.ti.x, it.ti.y);
1535 assert(IsValidTile(cur_tile)); // checked before in CheckIfIndustryTilesAreFree
1536
1537 if (gfx != GFX_WATERTILE_SPECIALCHECK) {
1538 const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
1539
1541 custom_shape = true;
1542 CommandCost ret = PerformIndustryTileSlopeCheck(tile, cur_tile, its, type, gfx, layout_index, initial_random_bits, founder, creation_type);
1543 if (ret.Failed()) return ret;
1544 } else {
1545 Slope tileh = GetTileSlope(cur_tile);
1546 refused_slope |= IsSlopeRefused(tileh, its->slopes_refused);
1547 }
1548 }
1549 }
1550
1551 if (custom_shape_check != nullptr) *custom_shape_check = custom_shape;
1552
1553 /* It is almost impossible to have a fully flat land in TG, so what we
1554 * do is that we check if we can make the land flat later on. See
1555 * CheckIfCanLevelIndustryPlatform(). */
1556 if (!refused_slope || (_settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world && !custom_shape && !_ignore_industry_restrictions)) {
1557 return CommandCost();
1558 }
1559 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1560}
1561
1569static CommandCost CheckIfIndustryIsAllowed(TileIndex tile, IndustryType type, const Town *t)
1570{
1571 if (GetIndustrySpec(type)->behaviour.Test(IndustryBehaviour::Town1200More) && t->cache.population < 1200) {
1572 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200);
1573 }
1574
1575 if (GetIndustrySpec(type)->behaviour.Test(IndustryBehaviour::OnlyNearTown) && DistanceMax(t->xy, tile) > 9) {
1576 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER);
1577 }
1578
1579 return CommandCost();
1580}
1581
1582static bool CheckCanTerraformSurroundingTiles(TileIndex tile, uint height, int internal)
1583{
1584 /* Check if we don't leave the map */
1585 if (TileX(tile) == 0 || TileY(tile) == 0 || GetTileType(tile) == MP_VOID) return false;
1586
1587 TileArea ta(tile - TileDiffXY(1, 1), 2, 2);
1588 for (TileIndex tile_walk : ta) {
1589 uint curh = TileHeight(tile_walk);
1590 /* Is the tile clear? */
1591 if ((GetTileType(tile_walk) != MP_CLEAR) && (GetTileType(tile_walk) != MP_TREES)) return false;
1592
1593 /* Don't allow too big of a change if this is the sub-tile check */
1594 if (internal != 0 && Delta(curh, height) > 1) return false;
1595
1596 /* Different height, so the surrounding tiles of this tile
1597 * has to be correct too (in level, or almost in level)
1598 * else you get a chain-reaction of terraforming. */
1599 if (internal == 0 && curh != height) {
1600 if (TileX(tile_walk) == 0 || TileY(tile_walk) == 0 || !CheckCanTerraformSurroundingTiles(tile_walk + TileDiffXY(-1, -1), height, internal + 1)) {
1601 return false;
1602 }
1603 }
1604 }
1605
1606 return true;
1607}
1608
1614{
1615 int max_x = 0;
1616 int max_y = 0;
1617
1618 /* Finds dimensions of largest variant of this industry */
1619 for (const IndustryTileLayoutTile &it : layout) {
1620 if (it.gfx == GFX_WATERTILE_SPECIALCHECK) continue; // watercheck tiles don't count for footprint size
1621 if (it.ti.x > max_x) max_x = it.ti.x;
1622 if (it.ti.y > max_y) max_y = it.ti.y;
1623 }
1624
1625 /* Remember level height */
1626 uint h = TileHeight(tile);
1627
1629 /* Check that all tiles in area and surrounding are clear
1630 * this determines that there are no obstructing items */
1631
1632 /* TileArea::Expand is not used here as we need to abort
1633 * instead of clamping if the bounds cannot expanded. */
1636
1637 if (TileX(ta.tile) + ta.w >= Map::MaxX() || TileY(ta.tile) + ta.h >= Map::MaxY()) return false;
1638
1639 /* _current_company is OWNER_NONE for randomly generated industries and in editor, or the company who funded or prospected the industry.
1640 * Perform terraforming as OWNER_TOWN to disable autoslope and town ratings. */
1642
1643 for (TileIndex tile_walk : ta) {
1644 uint curh = TileHeight(tile_walk);
1645 if (curh != h) {
1646 /* This tile needs terraforming. Check if we can do that without
1647 * damaging the surroundings too much. */
1648 if (!CheckCanTerraformSurroundingTiles(tile_walk, h, 0)) {
1649 cur_company.Restore();
1650 return false;
1651 }
1652 /* This is not 100% correct check, but the best we can do without modifying the map.
1653 * What is missing, is if the difference in height is more than 1.. */
1654 if (std::get<0>(Command<CMD_TERRAFORM_LAND>::Do(DoCommandFlags{flags}.Reset(DoCommandFlag::Execute), tile_walk, SLOPE_N, curh <= h)).Failed()) {
1655 cur_company.Restore();
1656 return false;
1657 }
1658 }
1659 }
1660
1661 if (flags.Test(DoCommandFlag::Execute)) {
1662 /* Terraform the land under the industry */
1663 for (TileIndex tile_walk : ta) {
1664 uint curh = TileHeight(tile_walk);
1665 while (curh != h) {
1666 /* We give the terraforming for free here, because we can't calculate
1667 * exact cost in the test-round, and as we all know, that will cause
1668 * a nice assert if they don't match ;) */
1669 Command<CMD_TERRAFORM_LAND>::Do(flags, tile_walk, SLOPE_N, curh <= h);
1670 curh += (curh > h) ? -1 : 1;
1671 }
1672 }
1673 }
1674
1675 cur_company.Restore();
1676 return true;
1677}
1678
1679
1687{
1688 const IndustrySpec *indspec = GetIndustrySpec(type);
1689
1690 for (IndustryType conflicting_type : indspec->conflicting) {
1691 if (conflicting_type == IT_INVALID) continue;
1692
1693 for (const IndustryID &industry : Industry::industries[conflicting_type]) {
1694 /* Within 14 tiles from another industry is considered close */
1695 if (DistanceMax(tile, Industry::Get(industry)->location.tile) > 14) continue;
1696
1697 return CommandCost(STR_ERROR_INDUSTRY_TOO_CLOSE);
1698 }
1699 }
1700 return CommandCost();
1701}
1702
1707static void AdvertiseIndustryOpening(const Industry *ind)
1708{
1709 const IndustrySpec *ind_spc = GetIndustrySpec(ind->type);
1710 EncodedString headline;
1711 if (ind_spc->new_industry_text > STR_LAST_STRINGID) {
1712 headline = GetEncodedString(ind_spc->new_industry_text, ind_spc->name, STR_TOWN_NAME, ind->town->index);
1713 } else {
1714 headline = GetEncodedString(ind_spc->new_industry_text, ind_spc->name, ind->town->index);
1715 }
1716 AddIndustryNewsItem(std::move(headline), NewsType::IndustryOpen, ind->index);
1717 AI::BroadcastNewEvent(new ScriptEventIndustryOpen(ind->index));
1718 Game::NewEvent(new ScriptEventIndustryOpen(ind->index));
1719}
1720
1727{
1729 /* Industry has a neutral station. Use it and ignore any other nearby stations. */
1730 ind->stations_near.insert(ind->neutral_station);
1731 ind->neutral_station->industries_near.clear();
1733 return;
1734 }
1735
1736 ForAllStationsAroundTiles(ind->location, [ind](Station *st, TileIndex tile) {
1737 if (!IsTileType(tile, MP_INDUSTRY) || GetIndustryIndex(tile) != ind->index) return false;
1738 ind->stations_near.insert(st);
1739 st->AddIndustryToDeliver(ind, tile);
1740 return false;
1741 });
1742}
1743
1755static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, const IndustryTileLayout &layout, size_t layout_index, Town *t, Owner founder, uint16_t initial_random_bits)
1756{
1757 const IndustrySpec *indspec = GetIndustrySpec(type);
1758
1759 i->location = TileArea(tile, 1, 1);
1760 i->type = type;
1761
1762 auto &industries = Industry::industries[type];
1763 industries.insert(i->index);
1764
1765 size_t produced_count = 0;
1766 for (size_t index = 0; index < std::size(indspec->produced_cargo); ++index) {
1767 if (IsValidCargoType(indspec->produced_cargo[index])) {
1768 produced_count = index + 1;
1769 }
1770 }
1771 for (size_t index = 0; index < produced_count; ++index) {
1772 Industry::ProducedCargo &p = i->produced.emplace_back();
1773 p.cargo = indspec->produced_cargo[index];
1774 p.rate = indspec->production_rate[index];
1775 }
1776
1777 size_t accepted_count = 0;
1778 for (size_t index = 0; index < std::size(indspec->accepts_cargo); ++index) {
1779 if (IsValidCargoType(indspec->accepts_cargo[index])) {
1780 accepted_count = index + 1;
1781 }
1782 }
1783 for (size_t index = 0; index < accepted_count; ++index) {
1784 Industry::AcceptedCargo &a = i->accepted.emplace_back();
1785 a.cargo = indspec->accepts_cargo[index];
1786 }
1787
1788 /* Randomize initial production if non-original economy is used and there are no production related callbacks. */
1789 if (!indspec->UsesOriginalEconomy()) {
1790 for (auto &p : i->produced) {
1791 p.rate = ClampTo<uint8_t>((RandomRange(256) + 128) * p.rate >> 8);
1792 }
1793 }
1794
1795 i->town = t;
1796 i->owner = OWNER_NONE;
1797
1798 uint16_t r = Random();
1799 i->random_colour = static_cast<Colours>(GB(r, 0, 4));
1800 i->counter = GB(r, 4, 12);
1801 i->random = initial_random_bits;
1802 i->was_cargo_delivered = false;
1804 i->founder = founder;
1805 i->ctlflags = {};
1806
1808 i->construction_type = (_game_mode == GM_EDITOR) ? ICT_SCENARIO_EDITOR :
1810
1811 /* Adding 1 here makes it conform to specs of var44 of varaction2 for industries
1812 * 0 = created prior of newindustries
1813 * else, chosen layout + 1 */
1814 i->selected_layout = (uint8_t)(layout_index + 1);
1815
1818
1820
1821 /* Call callbacks after the regular fields got initialised. */
1822
1825 if (res != CALLBACK_FAILED) {
1826 if (res < PRODLEVEL_MINIMUM || res > PRODLEVEL_MAXIMUM) {
1828 } else {
1829 i->prod_level = res;
1831 }
1832 }
1833 }
1834
1835 if (_generating_world) {
1838 for (auto &p : i->produced) {
1839 if (IsValidCargoType(p.cargo)) p.history[LAST_MONTH].production = ScaleByCargoScale(p.waiting * 8, false);
1840 p.waiting = 0;
1841 }
1842 }
1843
1844 for (auto &p : i->produced) {
1845 if (IsValidCargoType(p.cargo)) p.history[LAST_MONTH].production += ScaleByCargoScale(p.rate * 8, false);
1846 }
1847
1849 }
1850
1852 uint16_t res = GetIndustryCallback(CBID_INDUSTRY_DECIDE_COLOUR, 0, 0, i, type, INVALID_TILE);
1853 if (res != CALLBACK_FAILED) {
1854 if (GB(res, 4, 11) != 0) ErrorUnknownCallbackResult(indspec->grf_prop.grfid, CBID_INDUSTRY_DECIDE_COLOUR, res);
1855 i->random_colour = static_cast<Colours>(GB(res, 0, 4));
1856 }
1857 }
1858
1860 /* Clear all input cargo types */
1861 i->accepted.clear();
1862 /* Query actual types */
1864 for (uint j = 0; j < maxcargoes; j++) {
1866 if (res == CALLBACK_FAILED || GB(res, 0, 8) == UINT8_MAX) break;
1867 if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
1869 break;
1870 }
1871 CargoType cargo = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
1872 /* Industries without "unlimited" cargo types support depend on the specific order/slots of cargo types.
1873 * They need to be able to blank out specific slots without aborting the callback sequence,
1874 * and solve this by returning undefined cargo indexes. Skip these. */
1876 /* As slots are allocated as needed now, this means we do need to add a slot for the invalid cargo. */
1877 Industry::AcceptedCargo &a = i->accepted.emplace_back();
1878 a.cargo = INVALID_CARGO;
1879 continue;
1880 }
1881 /* Verify valid cargo */
1882 if (std::ranges::find(indspec->accepts_cargo, cargo) == std::end(indspec->accepts_cargo)) {
1883 /* Cargo not in spec, error in NewGRF */
1885 break;
1886 }
1887 if (std::any_of(std::begin(i->accepted), std::begin(i->accepted) + j, [&cargo](const auto &a) { return a.cargo == cargo; })) {
1888 /* Duplicate cargo */
1890 break;
1891 }
1892 Industry::AcceptedCargo &a = i->accepted.emplace_back();
1893 a.cargo = cargo;
1894 }
1895 }
1896
1898 /* Clear all output cargo types */
1899 i->produced.clear();
1900 /* Query actual types */
1902 for (uint j = 0; j < maxcargoes; j++) {
1904 if (res == CALLBACK_FAILED || GB(res, 0, 8) == UINT8_MAX) break;
1905 if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
1907 break;
1908 }
1909 CargoType cargo = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
1910 /* Allow older GRFs to skip slots. */
1912 /* As slots are allocated as needed now, this means we do need to add a slot for the invalid cargo. */
1913 Industry::ProducedCargo &p = i->produced.emplace_back();
1914 p.cargo = INVALID_CARGO;
1915 continue;
1916 }
1917 /* Verify valid cargo */
1918 if (std::ranges::find(indspec->produced_cargo, cargo) == std::end(indspec->produced_cargo)) {
1919 /* Cargo not in spec, error in NewGRF */
1921 break;
1922 }
1923 if (std::any_of(std::begin(i->produced), std::begin(i->produced) + j, [&cargo](const auto &p) { return p.cargo == cargo; })) {
1924 /* Duplicate cargo */
1926 break;
1927 }
1928 Industry::ProducedCargo &p = i->produced.emplace_back();
1929 p.cargo = cargo;
1930 }
1931 }
1932
1933 /* Plant the tiles */
1934
1935 for (const IndustryTileLayoutTile &it : layout) {
1936 TileIndex cur_tile = tile + ToTileIndexDiff(it.ti);
1937
1938 if (it.gfx != GFX_WATERTILE_SPECIALCHECK) {
1939 i->location.Add(cur_tile);
1940
1941 WaterClass wc = (IsWaterTile(cur_tile) ? GetWaterClass(cur_tile) : WaterClass::Invalid);
1942
1944
1945 MakeIndustry(cur_tile, i->index, it.gfx, Random(), wc);
1946
1947 if (_generating_world) {
1948 SetIndustryConstructionCounter(cur_tile, 3);
1949 SetIndustryConstructionStage(cur_tile, 2);
1950 }
1951
1952 /* it->gfx is stored in the map. But the translated ID cur_gfx is the interesting one */
1953 IndustryGfx cur_gfx = GetTranslatedIndustryTileID(it.gfx);
1954 const IndustryTileSpec *its = GetIndustryTileSpec(cur_gfx);
1955 if (its->animation.status != AnimationStatus::NoAnimation) AddAnimatedTile(cur_tile);
1956 }
1957 }
1958
1959 /* Call callbacks after all tiles have been created. */
1960 for (TileIndex cur_tile : i->location) {
1961 if (i->TileBelongsToIndustry(cur_tile)) {
1962 /* There are no shared random bits, consistent with "MakeIndustryTileBigger" in tile loop.
1963 * So, trigger tiles individually */
1964 TriggerIndustryTileAnimation_ConstructionStageChanged(cur_tile, true);
1965 }
1966 }
1967
1969 for (uint j = 0; j != 50; j++) PlantRandomFarmField(i);
1970 }
1971 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, IDIWD_FORCE_REBUILD);
1973
1975}
1976
1993static 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)
1994{
1995 assert(layout_index < indspec->layouts.size());
1996 const IndustryTileLayout &layout = indspec->layouts[layout_index];
1997
1998 *ip = nullptr;
1999
2000 /* 1. Cheap: Built-in checks on industry level. */
2002 if (ret.Failed()) return ret;
2003
2004 Town *t = nullptr;
2005 ret = FindTownForIndustry(tile, type, &t);
2006 if (ret.Failed()) return ret;
2007 assert(t != nullptr);
2008
2009 ret = CheckIfIndustryIsAllowed(tile, type, t);
2010 if (ret.Failed()) return ret;
2011
2012 /* 2. Built-in checks on industry tiles. */
2013 std::vector<ClearedObjectArea> object_areas(_cleared_object_areas);
2014 ret = CheckIfIndustryTilesAreFree(tile, layout, type);
2015 _cleared_object_areas = std::move(object_areas);
2016 if (ret.Failed()) return ret;
2017
2018 /* 3. NewGRF-defined checks on industry level. */
2019 if (GetIndustrySpec(type)->callback_mask.Test(IndustryCallbackMask::Location)) {
2020 ret = CheckIfCallBackAllowsCreation(tile, type, layout_index, random_var8f, random_initial_bits, founder, creation_type);
2021 } else {
2022 ret = _check_new_industry_procs[indspec->check_proc](tile);
2023 }
2024 if (ret.Failed()) return ret;
2025
2026 /* 4. Expensive: NewGRF-defined checks on industry tiles. */
2027 bool custom_shape_check = false;
2028 ret = CheckIfIndustryTileSlopes(tile, layout, layout_index, type, random_initial_bits, founder, creation_type, &custom_shape_check);
2029 if (ret.Failed()) return ret;
2030
2032 !_ignore_industry_restrictions && !CheckIfCanLevelIndustryPlatform(tile, DoCommandFlag::NoWater, layout)) {
2033 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
2034 }
2035
2036 if (!Industry::CanAllocateItem()) return CommandCost(STR_ERROR_TOO_MANY_INDUSTRIES);
2037
2038 if (flags.Test(DoCommandFlag::Execute)) {
2039 *ip = new Industry(tile);
2040 if (!custom_shape_check) CheckIfCanLevelIndustryPlatform(tile, {DoCommandFlag::NoWater, DoCommandFlag::Execute}, layout);
2041 DoCreateNewIndustry(*ip, tile, type, layout, layout_index, t, founder, random_initial_bits);
2042 }
2043
2044 return CommandCost();
2045}
2046
2057CommandCost CmdBuildIndustry(DoCommandFlags flags, TileIndex tile, IndustryType it, uint32_t first_layout, bool fund, uint32_t seed)
2058{
2059 if (it >= NUM_INDUSTRYTYPES) return CMD_ERROR;
2060
2061 const IndustrySpec *indspec = GetIndustrySpec(it);
2062
2063 /* Check if the to-be built/founded industry is available for this climate. */
2064 if (!indspec->enabled || indspec->layouts.empty()) return CMD_ERROR;
2065
2066 /* If the setting for raw-material industries is not on, you cannot build raw-material industries.
2067 * Raw material industries are industries that do not accept cargo (at least for now) */
2068 if (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 0 && indspec->IsRawIndustry()) {
2069 return CMD_ERROR;
2070 }
2071
2072 if (_game_mode != GM_EDITOR && GetIndustryProbabilityCallback(it, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, 1) == 0) {
2073 return CMD_ERROR;
2074 }
2075
2076 Randomizer randomizer;
2077 randomizer.SetSeed(seed);
2078 uint16_t random_initial_bits = GB(seed, 0, 16);
2079 uint32_t random_var8f = randomizer.Next();
2080 size_t num_layouts = indspec->layouts.size();
2081 CommandCost ret = CommandCost(STR_ERROR_SITE_UNSUITABLE);
2082 const bool deity_prospect = _current_company == OWNER_DEITY && !fund;
2083
2084 Industry *ind = nullptr;
2085 if (deity_prospect || (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 2 && indspec->IsRawIndustry())) {
2086 if (flags.Test(DoCommandFlag::Execute)) {
2087 /* Prospecting has a chance to fail, however we cannot guarantee that something can
2088 * be built on the map, so the chance gets lower when the map is fuller, but there
2089 * is nothing we can really do about that. */
2090 bool prospect_success = deity_prospect || Random() <= indspec->prospecting_chance;
2091 if (prospect_success) {
2092 /* Prospected industries are build as OWNER_TOWN to not e.g. be build on owned land of the founder */
2095 for (int i = 0; i < 5000; i++) {
2096 /* We should not have more than one Random() in a function call
2097 * because parameter evaluation order is not guaranteed in the c++ standard
2098 */
2099 tile = RandomTile();
2100 /* Start with a random layout */
2101 size_t layout = RandomRange((uint32_t)num_layouts);
2102 /* Check now each layout, starting with the random one */
2103 for (size_t j = 0; j < num_layouts; j++) {
2104 layout = (layout + 1) % num_layouts;
2105 ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, cur_company.GetOriginalValue(), calltype, &ind);
2106 if (ret.Succeeded()) break;
2107 }
2108 if (ret.Succeeded()) break;
2109 }
2110 cur_company.Restore();
2111 }
2112 if (ret.Failed() && IsLocalCompany()) {
2113 if (prospect_success) {
2114 ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_PROSPECT_INDUSTRY), GetEncodedString(STR_ERROR_NO_SUITABLE_PLACES_FOR_PROSPECTING), WL_INFO);
2115 } else {
2116 ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_PROSPECT_INDUSTRY), GetEncodedString(STR_ERROR_PROSPECTING_WAS_UNLUCKY), WL_INFO);
2117 }
2118 }
2119 }
2120 } else {
2121 size_t layout = first_layout;
2122 if (layout >= num_layouts) return CMD_ERROR;
2123
2124 /* Check subsequently each layout, starting with the given layout in p1 */
2125 for (size_t i = 0; i < num_layouts; i++) {
2126 layout = (layout + 1) % num_layouts;
2127 ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, _current_company, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, &ind);
2128 if (ret.Succeeded()) break;
2129 }
2130
2131 /* If it still failed, there's no suitable layout to build here, return the error */
2132 if (ret.Failed()) return ret;
2133 }
2134
2135 if (flags.Test(DoCommandFlag::Execute) && ind != nullptr && _game_mode != GM_EDITOR) {
2137 }
2138
2140}
2141
2150{
2151 if (_current_company != OWNER_DEITY) return CMD_ERROR;
2152
2153 Industry *ind = Industry::GetIfValid(ind_id);
2154 if (ind == nullptr) return CMD_ERROR;
2155 if (!ctlflags.IsValid()) return CMD_ERROR;
2156
2157 if (flags.Test(DoCommandFlag::Execute)) ind->ctlflags = ctlflags;
2158
2159 return CommandCost();
2160}
2161
2171CommandCost CmdIndustrySetProduction(DoCommandFlags flags, IndustryID ind_id, uint8_t prod_level, bool show_news, const EncodedString &custom_news)
2172{
2173 if (_current_company != OWNER_DEITY) return CMD_ERROR;
2174 if (prod_level < PRODLEVEL_MINIMUM || prod_level > PRODLEVEL_MAXIMUM) return CMD_ERROR;
2175
2176 Industry *ind = Industry::GetIfValid(ind_id);
2177 if (ind == nullptr) return CMD_ERROR;
2178
2179 if (flags.Test(DoCommandFlag::Execute)) {
2181 ind->prod_level = prod_level;
2183
2184 /* Show news message if requested. */
2185 if (show_news && prod_level != ind->prod_level) {
2186 NewsType nt;
2187 switch (WhoCanServiceIndustry(ind)) {
2188 case 0: nt = NewsType::IndustryNobody; break;
2189 case 1: nt = NewsType::IndustryOther; break;
2190 case 2: nt = NewsType::IndustryCompany; break;
2191 default: NOT_REACHED();
2192 }
2193
2194 /* Set parameters of news string */
2195 EncodedString headline;
2196 if (!custom_news.empty()) {
2197 headline = custom_news;
2198 } else {
2199 StringID str = (prod_level > ind->prod_level)
2202
2203 if (str > STR_LAST_STRINGID) {
2204 headline = GetEncodedString(str, STR_TOWN_NAME, ind->town->index, GetIndustrySpec(ind->type)->name);
2205 } else {
2206 headline = GetEncodedString(str, ind->index);
2207 }
2208 }
2209
2210 AddIndustryNewsItem(std::move(headline), nt, ind->index);
2211 }
2212 }
2213
2214 return CommandCost();
2215}
2216
2227{
2228 if (_current_company != OWNER_DEITY) return CMD_ERROR;
2229
2230 Industry *ind = Industry::GetIfValid(ind_id);
2231 if (ind == nullptr) return CMD_ERROR;
2232
2233 if (company_id != OWNER_NONE && company_id != INVALID_OWNER && company_id != OWNER_DEITY
2234 && !Company::IsValidID(company_id)) return CMD_ERROR;
2235
2236 if (flags.Test(DoCommandFlag::Execute)) {
2237 if (consumer) {
2238 ind->exclusive_consumer = company_id;
2239 } else {
2240 ind->exclusive_supplier = company_id;
2241 }
2242 }
2243
2244
2245 return CommandCost();
2246}
2247
2256{
2257 if (_current_company != OWNER_DEITY) return CMD_ERROR;
2258
2259 Industry *ind = Industry::GetIfValid(ind_id);
2260 if (ind == nullptr) return CMD_ERROR;
2261
2262 if (flags.Test(DoCommandFlag::Execute)) {
2263 ind->text.clear();
2264 if (!text.empty()) ind->text = text;
2266 }
2267
2268 return CommandCost();
2269}
2270
2278static Industry *CreateNewIndustry(TileIndex tile, IndustryType type, IndustryAvailabilityCallType creation_type)
2279{
2280 const IndustrySpec *indspec = GetIndustrySpec(type);
2281
2282 uint32_t seed = Random();
2283 uint32_t seed2 = Random();
2284 Industry *i = nullptr;
2285 size_t layout_index = RandomRange((uint32_t)indspec->layouts.size());
2286 [[maybe_unused]] CommandCost ret = CreateNewIndustryHelper(tile, type, DoCommandFlag::Execute, indspec, layout_index, seed, GB(seed2, 0, 16), OWNER_NONE, creation_type, &i);
2287 assert(i != nullptr || ret.Failed());
2288 return i;
2289}
2290
2298static uint32_t GetScaledIndustryGenerationProbability(IndustryType it, std::optional<bool> water, bool *force_at_least_one)
2299{
2300 const IndustrySpec *ind_spc = GetIndustrySpec(it);
2301 if (water.has_value() && ind_spc->behaviour.Test(IndustryBehaviour::BuiltOnWater) != *water) return 0;
2302
2304 if (!ind_spc->enabled || ind_spc->layouts.empty() ||
2305 (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == ID_FUND_ONLY) ||
2306 (chance = GetIndustryProbabilityCallback(it, IACT_MAPGENERATION, chance)) == 0) {
2307 *force_at_least_one = false;
2308 return 0;
2309 } else {
2310 chance *= 16; // to increase precision
2311 /* We want industries appearing at coast to appear less often on bigger maps, as length of coast increases slower than map area.
2312 * For simplicity we scale in both cases, though scaling the probabilities of all industries has no effect. */
2313 chance = (ind_spc->check_proc == CHECK_REFINERY || ind_spc->check_proc == CHECK_OIL_RIG) ? Map::ScaleBySize1D(chance) : Map::ScaleBySize(chance);
2314
2315 *force_at_least_one = (chance > 0) && !ind_spc->behaviour.Test(IndustryBehaviour::NoBuildMapCreation) && (_game_mode != GM_EDITOR);
2316 return chance;
2317 }
2318}
2319
2326static uint16_t GetIndustryGamePlayProbability(IndustryType it, uint8_t *min_number)
2327{
2329 *min_number = 0;
2330 return 0;
2331 }
2332
2333 const IndustrySpec *ind_spc = GetIndustrySpec(it);
2335 if (!ind_spc->enabled || ind_spc->layouts.empty() ||
2338 (chance = GetIndustryProbabilityCallback(it, IACT_RANDOMCREATION, chance)) == 0) {
2339 *min_number = 0;
2340 return 0;
2341 }
2342 *min_number = ind_spc->behaviour.Test(IndustryBehaviour::CanCloseLastInstance) ? 1 : 0;
2343 return chance;
2344}
2345
2351{
2352 /* Number of industries on a 256x256 map. */
2353 static const uint16_t numof_industry_table[] = {
2354 0, // none
2355 0, // minimal
2356 10, // very low
2357 25, // low
2358 55, // normal
2359 80, // high
2360 0, // custom
2361 };
2362
2363 assert(lengthof(numof_industry_table) == ID_END);
2364 uint difficulty = (_game_mode != GM_EDITOR) ? _settings_game.difficulty.industry_density : (uint)ID_VERY_LOW;
2365
2366 if (difficulty == ID_CUSTOM) return std::min<uint>(IndustryPool::MAX_SIZE, _settings_game.game_creation.custom_industry_number);
2367
2368 return std::min<uint>(IndustryPool::MAX_SIZE, Map::ScaleBySize(numof_industry_table[difficulty]));
2369}
2370
2379static Industry *PlaceIndustry(IndustryType type, IndustryAvailabilityCallType creation_type, bool try_hard)
2380{
2381 uint tries = try_hard ? 10000u : 2000u;
2382 for (; tries > 0; tries--) {
2383 Industry *ind = CreateNewIndustry(RandomTile(), type, creation_type);
2384 if (ind != nullptr) return ind;
2385 }
2386 return nullptr;
2387}
2388
2394static void PlaceInitialIndustry(IndustryType type, bool water, bool try_hard)
2395{
2397
2399 PlaceIndustry(type, IACT_MAPGENERATION, try_hard);
2400
2401 cur_company.Restore();
2402}
2403
2409{
2410 uint total = 0;
2411 for (const auto &industries : Industry::industries) {
2412 total += static_cast<uint16_t>(std::size(industries));
2413 }
2414 return total;
2415}
2416
2417
2420{
2421 this->probability = 0;
2422 this->min_number = 0;
2423 this->target_count = 0;
2424 this->max_wait = 1;
2425 this->wait_count = 0;
2426}
2427
2430{
2432
2433 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2434 this->builddata[it].Reset();
2435 }
2436}
2437
2440{
2441 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.
2442 if (_settings_game.difficulty.industry_density == ID_FUND_ONLY) return; // 'no industries' setting.
2443
2444 /* To prevent running out of unused industries for the player to connect,
2445 * add a fraction of new industries each month, but only if the manager can keep up. */
2446 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).
2447 if (GetCurrentTotalNumberOfIndustries() + max_behind >= (this->wanted_inds >> 16)) {
2448 this->wanted_inds += Map::ScaleBySize(NEWINDS_PER_MONTH);
2449 }
2450}
2451
2453 std::array<uint32_t, NUM_INDUSTRYTYPES> probs{};
2454 std::array<bool, NUM_INDUSTRYTYPES> force_one{};
2455 uint64_t total = 0;
2456 uint num_forced = 0;
2457};
2458
2465{
2467
2468 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2469 p.probs[it] = GetScaledIndustryGenerationProbability(it, water, &p.force_one[it]);
2470 p.total += p.probs[it];;
2471 if (p.force_one[it]) p.num_forced++;
2472 }
2473
2474 return p;
2475}
2476
2482{
2483 if (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == ID_FUND_ONLY) return; // No industries in the game.
2484
2485 /* Get the probabilities for all industries. This is done first as we need the total of
2486 * both land and water for scaling later. */
2489
2490 /* Run generation twice, for land and water industries in turn. */
2491 for (bool water = false;; water = true) {
2492 auto &p = water ? wprob : lprob;
2493
2494 /* Total number of industries scaled by land/water proportion. */
2495 uint total_amount = p.total * GetNumberOfIndustries() / (lprob.total + wprob.total);
2496
2497 /* Scale land-based industries to the land proportion, unless the player has set a custom industry count. */
2498 if (!water && _settings_game.difficulty.industry_density != ID_CUSTOM) total_amount = Map::ScaleByLandProportion(total_amount);
2499
2500 /* Ensure that forced industries are generated even if the scaled amounts are too low. */
2501 if (p.total == 0 || total_amount < p.num_forced) {
2502 /* Only place the forced ones */
2503 total_amount = p.num_forced;
2504 }
2505
2507
2508 /* Try to build one industry per type independent of any probabilities */
2509 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2510 if (p.force_one[it]) {
2511 assert(total_amount > 0);
2512 total_amount--;
2513 PlaceInitialIndustry(it, water, true);
2514 }
2515 }
2516
2517 /* Add the remaining industries according to their probabilities */
2518 for (uint i = 0; i < total_amount; i++) {
2519 uint32_t r = RandomRange(p.total);
2520 IndustryType it = 0;
2521 while (r >= p.probs[it]) {
2522 r -= p.probs[it];
2523 it++;
2524 assert(it < NUM_INDUSTRYTYPES);
2525 }
2526 assert(p.probs[it] > 0);
2527 PlaceInitialIndustry(it, water, false);
2528 }
2529
2530 if (water) break;
2531 }
2532
2534}
2535
2536template <>
2537Industry::ProducedHistory SumHistory(std::span<const Industry::ProducedHistory> history)
2538{
2539 uint32_t production = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const auto &p) { return r + p.production; });
2540 uint32_t transported = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const auto &p) { return r + p.transported; });
2541 auto count = std::size(history);
2542 return {.production = ClampTo<uint16_t>(production / count), .transported = ClampTo<uint16_t>(transported / count)};
2543}
2544
2545template <>
2546Industry::AcceptedHistory SumHistory(std::span<const Industry::AcceptedHistory> history)
2547{
2548 uint32_t accepted = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const auto &a) { return r + a.accepted; });
2549 uint32_t waiting = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const auto &a) { return r + a.waiting; });;
2550 auto count = std::size(history);
2551 return {.accepted = ClampTo<uint16_t>(accepted / count), .waiting = ClampTo<uint16_t>(waiting / count)};
2552}
2553
2559{
2560 auto month = TimerGameEconomy::month;
2561 UpdateValidHistory(i->valid_history, HISTORY_YEAR, month);
2562
2563 for (auto &p : i->produced) {
2564 if (IsValidCargoType(p.cargo)) {
2565 if (p.history[THIS_MONTH].production != 0) i->last_prod_year = TimerGameEconomy::year;
2566
2567 RotateHistory(p.history, i->valid_history, HISTORY_YEAR, month);
2568 }
2569 }
2570
2571 for (auto &a : i->accepted) {
2572 if (!IsValidCargoType(a.cargo)) continue;
2573 if (a.history == nullptr) continue;
2574
2575 (*a.history)[THIS_MONTH].waiting = GetAndResetAccumulatedAverage<uint16_t>(a.accumulated_waiting);
2576 RotateHistory(*a.history, i->valid_history, HISTORY_YEAR, month);
2577 }
2578}
2579
2585{
2586 const IndustrySpec *indspec = GetIndustrySpec(this->type);
2587 assert(indspec->UsesOriginalEconomy());
2588
2589 /* Rates are rounded up, so e.g. oilrig always produces some passengers */
2590 for (auto &p : this->produced) {
2591 p.rate = ClampTo<uint8_t>(CeilDiv(indspec->production_rate[&p - this->produced.data()] * this->prod_level, PRODLEVEL_DEFAULT));
2592 }
2593}
2594
2595void Industry::FillCachedName() const
2596{
2597 auto tmp_params = MakeParameters(this->index);
2598 this->cached_name = GetStringWithArgs(STR_INDUSTRY_NAME, tmp_params);
2599}
2600
2601void ClearAllIndustryCachedNames()
2602{
2603 for (Industry *ind : Industry::Iterate()) {
2604 ind->cached_name.clear();
2605 }
2606}
2607
2614{
2615 uint8_t min_number;
2617 bool changed = min_number != this->min_number || probability != this->probability;
2618 this->min_number = min_number;
2619 this->probability = probability;
2620 return changed;
2621}
2622
2625{
2626 bool changed = false;
2627 uint num_planned = 0; // Number of industries planned in the industry build data.
2628 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2629 changed |= this->builddata[it].GetIndustryTypeData(it);
2630 num_planned += this->builddata[it].target_count;
2631 }
2632 uint total_amount = this->wanted_inds >> 16; // Desired total number of industries.
2633 changed |= num_planned != total_amount;
2634 if (!changed) return; // All industries are still the same, no need to re-randomize.
2635
2636 /* Initialize the target counts. */
2637 uint force_build = 0; // Number of industries that should always be available.
2638 uint32_t total_prob = 0; // Sum of probabilities.
2639 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2640 IndustryTypeBuildData *ibd = this->builddata + it;
2641 force_build += ibd->min_number;
2642 ibd->target_count = ibd->min_number;
2643 total_prob += ibd->probability;
2644 }
2645
2646 if (total_prob == 0) return; // No buildable industries.
2647
2648 /* Subtract forced industries from the number of industries available for construction. */
2649 total_amount = (total_amount <= force_build) ? 0 : total_amount - force_build;
2650
2651 /* Assign number of industries that should be aimed for, by using the probability as a weight. */
2652 while (total_amount > 0) {
2653 uint32_t r = RandomRange(total_prob);
2654 IndustryType it = 0;
2655 while (r >= this->builddata[it].probability) {
2656 r -= this->builddata[it].probability;
2657 it++;
2658 assert(it < NUM_INDUSTRYTYPES);
2659 }
2660 assert(this->builddata[it].probability > 0);
2661 this->builddata[it].target_count++;
2662 total_amount--;
2663 }
2664}
2665
2670{
2671 this->SetupTargetCount();
2672
2673 int missing = 0; // Number of industries that need to be build.
2674 uint count = 0; // Number of industry types eligible for build.
2675 uint32_t total_prob = 0; // Sum of probabilities.
2676 IndustryType forced_build = NUM_INDUSTRYTYPES; // Industry type that should be forcibly build.
2677 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2678 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
2679 missing += difference;
2680 if (this->builddata[it].wait_count > 0) continue; // This type may not be built now.
2681 if (difference > 0) {
2682 if (Industry::GetIndustryTypeCount(it) == 0 && this->builddata[it].min_number > 0) {
2683 /* An industry that should exist at least once, is not available. Force it, trying the most needed one first. */
2684 if (forced_build == NUM_INDUSTRYTYPES ||
2685 difference > this->builddata[forced_build].target_count - Industry::GetIndustryTypeCount(forced_build)) {
2686 forced_build = it;
2687 }
2688 }
2689 total_prob += difference;
2690 count++;
2691 }
2692 }
2693
2694 if (EconomyIsInRecession() || (forced_build == NUM_INDUSTRYTYPES && (missing <= 0 || total_prob == 0))) count = 0; // Skip creation of an industry.
2695
2696 if (count >= 1) {
2697 /* If not forced, pick a weighted random industry to build.
2698 * For the case that count == 1, there is no need to draw a random number. */
2699 IndustryType it;
2700 if (forced_build != NUM_INDUSTRYTYPES) {
2701 it = forced_build;
2702 } else {
2703 /* Non-forced, select an industry type to build (weighted random). */
2704 uint32_t r = 0; // Initialized to silence the compiler.
2705 if (count > 1) r = RandomRange(total_prob);
2706 for (it = 0; it < NUM_INDUSTRYTYPES; it++) {
2707 if (this->builddata[it].wait_count > 0) continue; // Type may not be built now.
2708 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
2709 if (difference <= 0) continue; // Too many of this kind.
2710 if (count == 1) break;
2711 if (r < (uint)difference) break;
2712 r -= difference;
2713 }
2714 assert(it < NUM_INDUSTRYTYPES && this->builddata[it].target_count > Industry::GetIndustryTypeCount(it));
2715 }
2716
2717 /* Try to create the industry. */
2718 const Industry *ind = PlaceIndustry(it, IACT_RANDOMCREATION, false);
2719 if (ind == nullptr) {
2720 this->builddata[it].wait_count = this->builddata[it].max_wait + 1; // Compensate for decrementing below.
2721 this->builddata[it].max_wait = std::min(1000, this->builddata[it].max_wait + 2);
2722 } else {
2724 this->builddata[it].max_wait = std::max(this->builddata[it].max_wait / 2, 1); // Reduce waiting time of the industry type.
2725 }
2726 }
2727
2728 /* Decrement wait counters. */
2729 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2730 if (this->builddata[it].wait_count > 0) this->builddata[it].wait_count--;
2731 }
2732}
2733
2742static bool CheckIndustryCloseDownProtection(IndustryType type)
2743{
2744 const IndustrySpec *indspec = GetIndustrySpec(type);
2745
2746 /* oil wells (or the industries with that flag set) are always allowed to closedown */
2747 if (indspec->behaviour.Test(IndustryBehaviour::DontIncrProd) && _settings_game.game_creation.landscape == LandscapeType::Temperate) return false;
2749}
2750
2760static void CanCargoServiceIndustry(CargoType cargo, Industry *ind, bool *c_accepts, bool *c_produces)
2761{
2762 if (!IsValidCargoType(cargo)) return;
2763
2764 /* Check for acceptance of cargo */
2765 if (ind->IsCargoAccepted(cargo) && !IndustryTemporarilyRefusesCargo(ind, cargo)) *c_accepts = true;
2766
2767 /* Check for produced cargo */
2768 if (ind->IsCargoProduced(cargo)) *c_produces = true;
2769}
2770
2785{
2786 if (ind->stations_near.empty()) return 0; // No stations found at all => nobody services
2787
2788 int result = 0;
2789 for (const Vehicle *v : Vehicle::Iterate()) {
2790 /* Is it worthwhile to try this vehicle? */
2791 if (v->owner != _local_company && result != 0) continue;
2792
2793 /* Check whether it accepts the right kind of cargo */
2794 bool c_accepts = false;
2795 bool c_produces = false;
2796 if (v->type == VEH_TRAIN && v->IsFrontEngine()) {
2797 for (const Vehicle *u = v; u != nullptr; u = u->Next()) {
2798 CanCargoServiceIndustry(u->cargo_type, ind, &c_accepts, &c_produces);
2799 }
2800 } else if (v->type == VEH_ROAD || v->type == VEH_SHIP || v->type == VEH_AIRCRAFT) {
2801 CanCargoServiceIndustry(v->cargo_type, ind, &c_accepts, &c_produces);
2802 } else {
2803 continue;
2804 }
2805 if (!c_accepts && !c_produces) continue; // Wrong cargo
2806
2807 /* Check orders of the vehicle.
2808 * We cannot check the first of shared orders only, since the first vehicle in such a chain
2809 * may have a different cargo type.
2810 */
2811 for (const Order &o : v->Orders()) {
2812 if (o.IsType(OT_GOTO_STATION) && !(o.GetUnloadType() & OUFB_TRANSFER)) {
2813 /* Vehicle visits a station to load or unload */
2814 Station *st = Station::Get(o.GetDestination().ToStationID());
2815 assert(st != nullptr);
2816
2817 /* Same cargo produced by industry is dropped here => not serviced by vehicle v */
2818 if ((o.GetUnloadType() & OUFB_UNLOAD) && !c_accepts) break;
2819
2820 if (ind->stations_near.find(st) != ind->stations_near.end()) {
2821 if (v->owner == _local_company) return 2; // Company services industry
2822 result = 1; // Competitor services industry
2823 }
2824 }
2825 }
2826 }
2827 return result;
2828}
2829
2837static void ReportNewsProductionChangeIndustry(Industry *ind, CargoType cargo, int percent)
2838{
2839 NewsType nt;
2840
2841 switch (WhoCanServiceIndustry(ind)) {
2842 case 0: nt = NewsType::IndustryNobody; break;
2843 case 1: nt = NewsType::IndustryOther; break;
2844 case 2: nt = NewsType::IndustryCompany; break;
2845 default: NOT_REACHED();
2846 }
2847 AddIndustryNewsItem(
2848 GetEncodedString(percent >= 0 ? STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH : STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH,
2849 CargoSpec::Get(cargo)->name, ind->index, abs(percent)
2850 ),
2851 nt,
2852 ind->index
2853 );
2854}
2855
2856static const uint PERCENT_TRANSPORTED_60 = 153;
2857static const uint PERCENT_TRANSPORTED_80 = 204;
2858
2864static void ChangeIndustryProduction(Industry *i, bool monthly)
2865{
2866 StringID str = STR_NULL;
2867 bool closeit = false;
2868 const IndustrySpec *indspec = GetIndustrySpec(i->type);
2869 bool standard = false;
2870 bool suppress_message = false;
2871 bool recalculate_multipliers = false;
2872 /* use original economy for industries using production related callbacks */
2873 bool original_economy = indspec->UsesOriginalEconomy();
2874 uint8_t div = 0;
2875 uint8_t mul = 0;
2876 int8_t increment = 0;
2877
2879 if (callback_enabled) {
2880 std::array<int32_t, 1> regs100;
2881 uint16_t res = GetIndustryCallback(monthly ? CBID_INDUSTRY_MONTHLYPROD_CHANGE : CBID_INDUSTRY_PRODUCTION_CHANGE, 0, Random(), i, i->type, i->location.tile, regs100);
2882 if (res != CALLBACK_FAILED) { // failed callback means "do nothing"
2883 suppress_message = HasBit(res, 7);
2884 /* Get the custom message if any */
2885 if (HasBit(res, 8)) str = MapGRFStringID(indspec->grf_prop.grfid, GRFStringID(GB(regs100[0], 0, 16)));
2886 res = GB(res, 0, 4);
2887 switch (res) {
2888 default: NOT_REACHED();
2889 case 0x0: break; // Do nothing, but show the custom message if any
2890 case 0x1: div = 1; break; // Halve industry production. If production reaches the quarter of the default, the industry is closed instead.
2891 case 0x2: mul = 1; break; // Double industry production if it hasn't reached eight times of the original yet.
2892 case 0x3: closeit = true; break; // The industry announces imminent closure, and is physically removed from the map next month.
2893 case 0x4: standard = true; break; // Do the standard random production change as if this industry was a primary one.
2894 case 0x5: case 0x6: case 0x7: // Divide production by 4, 8, 16
2895 case 0x8: div = res - 0x3; break; // Divide production by 32
2896 case 0x9: case 0xA: case 0xB: // Multiply production by 4, 8, 16
2897 case 0xC: mul = res - 0x7; break; // Multiply production by 32
2898 case 0xD: // decrement production
2899 case 0xE: // increment production
2900 increment = res == 0x0D ? -1 : 1;
2901 break;
2902 case 0xF: // Set production to third byte of register 0x100
2903 i->prod_level = Clamp(GB(regs100[0], 16, 8), PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
2904 recalculate_multipliers = true;
2905 break;
2906 }
2907 }
2908 } else {
2909 if (monthly == original_economy) return;
2910 if (!original_economy && _settings_game.economy.type == ET_FROZEN) return;
2911 if (indspec->life_type == INDUSTRYLIFE_BLACK_HOLE) return;
2912 }
2913
2914 if (standard || (!callback_enabled && indspec->life_type.Any({IndustryLifeType::Organic, IndustryLifeType::Extractive}))) {
2915 /* decrease or increase */
2916 bool only_decrease = indspec->behaviour.Test(IndustryBehaviour::DontIncrProd) && _settings_game.game_creation.landscape == LandscapeType::Temperate;
2917
2918 if (original_economy) {
2919 if (only_decrease || Chance16(1, 3)) {
2920 /* If more than 60% transported, 66% chance of increase, else 33% chance of increase */
2921 if (!only_decrease && (i->GetProduced(0).history[LAST_MONTH].PctTransported() > PERCENT_TRANSPORTED_60) != Chance16(1, 3)) {
2922 mul = 1; // Increase production
2923 } else {
2924 div = 1; // Decrease production
2925 }
2926 }
2927 } else if (_settings_game.economy.type == ET_SMOOTH) {
2929 for (auto &p : i->produced) {
2930 if (!IsValidCargoType(p.cargo)) continue;
2931 uint32_t r = Random();
2932 int old_prod, new_prod, percent;
2933 /* If over 60% is transported, mult is 1, else mult is -1. */
2934 int mult = (p.history[LAST_MONTH].PctTransported() > PERCENT_TRANSPORTED_60) ? 1 : -1;
2935
2936 new_prod = old_prod = p.rate;
2937
2938 /* For industries with only_decrease flags (temperate terrain Oil Wells),
2939 * the multiplier will always be -1 so they will only decrease. */
2940 if (only_decrease) {
2941 mult = -1;
2942 /* For normal industries, if over 60% is transported, 33% chance for decrease.
2943 * Bonus for very high station ratings (over 80%): 16% chance for decrease. */
2944 } else if (Chance16I(1, ((p.history[LAST_MONTH].PctTransported() > PERCENT_TRANSPORTED_80) ? 6 : 3), r)) {
2945 mult *= -1;
2946 }
2947
2948 /* 4.5% chance for 3-23% (or 1 unit for very low productions) production change,
2949 * determined by mult value. If mult = 1 prod. increases, else (-1) it decreases. */
2950 if (Chance16I(1, 22, r >> 16)) {
2951 new_prod += mult * (std::max(((RandomRange(50) + 10) * old_prod) >> 8, 1U));
2952 }
2953
2954 /* Prevent production to overflow or Oil Rig passengers to be over-"produced" */
2955 new_prod = Clamp(new_prod, 1, 255);
2956 if (IsValidCargoType(p.cargo) && p.cargo == GetCargoTypeByLabel(CT_PASSENGERS) && !indspec->behaviour.Test(IndustryBehaviour::NoPaxProdClamp)) {
2957 new_prod = Clamp(new_prod, 0, 16);
2958 }
2959
2960 /* If override flags are set, prevent actually changing production if any was decided on */
2961 if (i->ctlflags.Test(IndustryControlFlag::NoProductionDecrease) && new_prod < old_prod) continue;
2962 if (i->ctlflags.Test(IndustryControlFlag::NoProductionIncrease) && new_prod > old_prod) continue;
2963
2964 /* Do not stop closing the industry when it has the lowest possible production rate */
2965 if (new_prod == old_prod && old_prod > 1) {
2966 closeit = false;
2967 continue;
2968 }
2969
2970 percent = (old_prod == 0) ? 100 : (new_prod * 100 / old_prod - 100);
2971 p.rate = new_prod;
2972
2973 /* Close the industry when it has the lowest possible production rate */
2974 if (new_prod > 1) closeit = false;
2975
2976 if (abs(percent) >= 10) {
2977 ReportNewsProductionChangeIndustry(i, p.cargo, percent);
2978 }
2979 }
2980 }
2981 }
2982
2983 /* If override flags are set, prevent actually changing production if any was decided on */
2984 if (i->ctlflags.Test(IndustryControlFlag::NoProductionDecrease) && (div > 0 || increment < 0)) return;
2985 if (i->ctlflags.Test(IndustryControlFlag::NoProductionIncrease) && (mul > 0 || increment > 0)) return;
2987 div = 0;
2988 mul = 0;
2989 increment = 0;
2990 }
2991
2992 if (!callback_enabled && indspec->life_type.Test(IndustryLifeType::Processing)) {
2993 if (TimerGameEconomy::year - i->last_prod_year >= PROCESSING_INDUSTRY_ABANDONMENT_YEARS && Chance16(1, original_economy ? 2 : 180)) {
2994 closeit = true;
2995 }
2996 }
2997
2998 /* Increase if needed */
2999 while (mul-- != 0 && i->prod_level < PRODLEVEL_MAXIMUM) {
3000 i->prod_level = std::min<int>(i->prod_level * 2, PRODLEVEL_MAXIMUM);
3001 recalculate_multipliers = true;
3002 if (str == STR_NULL) str = indspec->production_up_text;
3003 }
3004
3005 /* Decrease if needed */
3006 while (div-- != 0 && !closeit) {
3007 if (i->prod_level == PRODLEVEL_MINIMUM) {
3008 closeit = true;
3009 break;
3010 } else {
3011 i->prod_level = std::max<int>(i->prod_level / 2, PRODLEVEL_MINIMUM);
3012 recalculate_multipliers = true;
3013 if (str == STR_NULL) str = indspec->production_down_text;
3014 }
3015 }
3016
3017 /* Increase or Decreasing the production level if needed */
3018 if (increment != 0) {
3019 if (increment < 0 && i->prod_level == PRODLEVEL_MINIMUM) {
3020 closeit = true;
3021 } else {
3023 recalculate_multipliers = true;
3024 }
3025 }
3026
3027 /* Recalculate production_rate
3028 * For non-smooth economy these should always be synchronized with prod_level */
3029 if (recalculate_multipliers) i->RecomputeProductionMultipliers();
3030
3031 /* Close if needed and allowed */
3035 str = indspec->closure_text;
3036 }
3037
3038 if (!suppress_message && str != STR_NULL) {
3039 NewsType nt;
3040 /* Compute news category */
3041 if (closeit) {
3043 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index));
3044 Game::NewEvent(new ScriptEventIndustryClose(i->index));
3045 } else {
3046 switch (WhoCanServiceIndustry(i)) {
3047 case 0: nt = NewsType::IndustryNobody; break;
3048 case 1: nt = NewsType::IndustryOther; break;
3049 case 2: nt = NewsType::IndustryCompany; break;
3050 default: NOT_REACHED();
3051 }
3052 }
3053 /* Set parameters of news string */
3054 EncodedString headline;
3055 if (str > STR_LAST_STRINGID) {
3056 headline = GetEncodedString(str, STR_TOWN_NAME, i->town->index, indspec->name);
3057 } else if (closeit) {
3058 headline = GetEncodedString(str, STR_FORMAT_INDUSTRY_NAME, i->town->index, indspec->name);
3059 } else {
3060 headline = GetEncodedString(str, i->index);
3061 }
3062 /* and report the news to the user */
3063 if (closeit) {
3064 AddTileNewsItem(std::move(headline), nt, i->location.tile + TileDiffXY(1, 1));
3065 } else {
3066 AddIndustryNewsItem(std::move(headline), nt, i->index);
3067 }
3068 }
3069}
3070
3078static const IntervalTimer<TimerGameEconomy> _economy_industries_daily({TimerGameEconomy::DAY, TimerGameEconomy::Priority::INDUSTRY}, [](auto)
3079{
3081
3082 /* Bits 16-31 of industry_construction_counter contain the number of industries to change/create today,
3083 * the lower 16 bit are a fractional part that might accumulate over several days until it
3084 * is sufficient for an industry. */
3085 uint16_t change_loop = _economy.industry_daily_change_counter >> 16;
3086
3087 /* Reset the active part of the counter, just keeping the "fractional part" */
3088 _economy.industry_daily_change_counter &= 0xFFFF;
3089
3090 if (change_loop == 0) {
3091 return; // Nothing to do? get out
3092 }
3093
3095
3096 /* perform the required industry changes for the day */
3097
3098 uint perc = 3; // Between 3% and 9% chance of creating a new industry.
3100 perc = std::min(9u, perc + (_industry_builder.wanted_inds >> 16) - GetCurrentTotalNumberOfIndustries());
3101 }
3102 for (uint16_t j = 0; j < change_loop; j++) {
3103 if (Chance16(perc, 100)) {
3105 } else {
3107 if (i != nullptr) {
3108 ChangeIndustryProduction(i, false);
3110 }
3111 }
3112 }
3113
3114 cur_company.Restore();
3115
3116 /* production-change */
3117 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, IDIWD_PRODUCTION_CHANGE);
3118});
3119
3120static const IntervalTimer<TimerGameEconomy> _economy_industries_monthly({TimerGameEconomy::MONTH, TimerGameEconomy::Priority::INDUSTRY}, [](auto)
3121{
3123
3125
3126 for (Industry *i : Industry::Iterate()) {
3128 if (i->prod_level == PRODLEVEL_CLOSURE) {
3129 delete i;
3130 } else {
3131 ChangeIndustryProduction(i, true);
3133 }
3134 }
3135
3136 cur_company.Restore();
3137
3138 /* production-change */
3139 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, IDIWD_PRODUCTION_CHANGE);
3140});
3141
3142
3143void InitializeIndustries()
3144{
3145 Industry::industries.fill({});
3146 _industry_sound_tile = TileIndex{};
3147
3149}
3150
3153{
3154 int count = 0;
3155 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
3156 if (Industry::GetIndustryTypeCount(it) > 0) continue; // Types of existing industries can be skipped.
3157
3158 bool force_at_least_one;
3159 uint32_t chance = GetScaledIndustryGenerationProbability(it, std::nullopt, &force_at_least_one);
3160 if (chance == 0 || !force_at_least_one) continue; // Types that are not available can be skipped.
3161
3162 const IndustrySpec *is = GetIndustrySpec(it);
3163 ShowErrorMessage(GetEncodedString(STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES, is->name),
3164 GetEncodedString(STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION), WL_WARNING);
3165
3166 count++;
3167 if (count >= 3) break; // Don't swamp the user with errors.
3168 }
3169}
3170
3179
3185{
3186 /* Lumber mills are neither raw nor processing */
3189}
3190
3196{
3197 /* Building raw industries like secondary uses different price base */
3198 return (_price[(_settings_game.construction.raw_industry_construction == 1 && this->IsRawIndustry()) ?
3199 PR_BUILD_INDUSTRY_RAW : PR_BUILD_INDUSTRY] * this->cost_multiplier) >> 8;
3200}
3201
3209{
3210 return (_price[PR_CLEAR_INDUSTRY] * this->removal_cost_multiplier) >> 8;
3211}
3212
3227
3228static CommandCost TerraformTile_Industry(TileIndex tile, DoCommandFlags flags, int z_new, Slope tileh_new)
3229{
3230 if (AutoslopeEnabled()) {
3231 /* We imitate here TTDP's behaviour:
3232 * - Both new and old slope must not be steep.
3233 * - TileMaxZ must not be changed.
3234 * - Allow autoslope by default.
3235 * - Disallow autoslope if callback succeeds and returns non-zero.
3236 */
3237 Slope tileh_old = GetTileSlope(tile);
3238 /* TileMaxZ must not be changed. Slopes must not be steep. */
3239 if (!IsSteepSlope(tileh_old) && !IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) {
3240 const IndustryGfx gfx = GetIndustryGfx(tile);
3241 const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
3242
3243 /* Call callback 3C 'disable autosloping for industry tiles'. */
3245 /* If the callback fails, allow autoslope. */
3246 uint16_t res = GetIndustryTileCallback(CBID_INDTILE_AUTOSLOPE, 0, 0, gfx, Industry::GetByTile(tile), tile);
3247 if (res == CALLBACK_FAILED || !ConvertBooleanCallback(itspec->grf_prop.grffile, CBID_INDTILE_AUTOSLOPE, res)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
3248 } else {
3249 /* allow autoslope */
3250 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
3251 }
3252 }
3253 }
3254 return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
3255}
3256
3257extern const TileTypeProcs _tile_type_industry_procs = {
3258 DrawTile_Industry, // draw_tile_proc
3259 GetSlopePixelZ_Industry, // get_slope_z_proc
3260 ClearTile_Industry, // clear_tile_proc
3261 AddAcceptedCargo_Industry, // add_accepted_cargo_proc
3262 GetTileDesc_Industry, // get_tile_desc_proc
3263 GetTileTrackStatus_Industry, // get_tile_track_status_proc
3264 ClickTile_Industry, // click_tile_proc
3265 AnimateTile_Industry, // animate_tile_proc
3266 TileLoop_Industry, // tile_loop_proc
3267 ChangeTileOwner_Industry, // change_tile_owner_proc
3268 nullptr, // add_produced_cargo_proc
3269 nullptr, // vehicle_enter_tile_proc
3270 GetFoundation_Industry, // get_foundation_proc
3271 TerraformTile_Industry, // terraform_tile_proc
3272 nullptr, // check_build_above_proc
3273};
3274
3275bool IndustryCompare::operator() (const IndustryListEntry &lhs, const IndustryListEntry &rhs) const
3276{
3277 /* Compare by distance first and use index as a tiebreaker. */
3278 return std::tie(lhs.distance, lhs.industry->index) < std::tie(rhs.distance, rhs.industry->index);
3279}
3280
3286{
3287 auto ita = std::find_if(std::rbegin(ind->accepted), std::rend(ind->accepted), [](const auto &a) { return IsValidCargoType(a.cargo); });
3288 ind->accepted.erase(ita.base(), std::end(ind->accepted));
3289 ind->accepted.shrink_to_fit();
3290
3291 auto itp = std::find_if(std::rbegin(ind->produced), std::rend(ind->produced), [](const auto &p) { return IsValidCargoType(p.cargo); });
3292 ind->produced.erase(itp.base(), std::end(ind->produced));
3293 ind->produced.shrink_to_fit();
3294}
Base functions for all AIs.
void AddAnimatedTile(TileIndex tile, bool mark_dirty)
Add the given tile to the animated tile table (if it does not exist yet).
void DeleteAnimatedTile(TileIndex tile, bool immediate)
Stops animation on the given tile.
Tile animation!
Functions related to autoslope.
bool AutoslopeEnabled()
Tests if autoslope is enabled for _current_company.
Definition autoslope.h:65
Class for backupping variables and making sure they are restored later.
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
bool IsBridgeAbove(Tile t)
checks if a bridge is set above the ground of this tile
Definition bridge_map.h:45
Tables with default industry layouts and behaviours.
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:23
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:106
static constexpr CargoLabel CT_PASSENGERS
Available types of cargo Labels may be re-used between different climates.
Definition cargo_type.h:31
Cheats _cheats
All the cheats.
Definition cheat.cpp:16
Types related to cheating.
static void BroadcastNewEvent(ScriptEvent *event, CompanyID skip_company=CompanyID::Invalid())
Broadcast a new event to all active AIs.
Definition ai_core.cpp:255
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Reset()
Reset all bits.
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.
Enum-as-bit-set wrapper.
static void NewEvent(class ScriptEvent *event)
Queue a new event for a Game Script.
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
void ResetOverride()
Resets the override, which is used while initializing game.
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:59
void SetFence(Tile t, DiagDirection side, uint h)
Sets the type of fence (and whether there is one) for the given border.
Definition clear_map.h:228
IndustryID GetIndustryIndexOfField(Tile t)
Get the industry (farm) that made the field.
Definition clear_map.h:183
@ CLEAR_FIELDS
3
Definition clear_map.h:23
@ CLEAR_DESERT
1,3
Definition clear_map.h:25
void SetIndustryIndexOfField(Tile t, IndustryID i)
Set the industry (farm) that made the field.
Definition clear_map.h:195
void MakeField(Tile t, uint field_type, IndustryID industry)
Make a (farm) field tile.
Definition clear_map.h:268
void SetClearCounter(Tile t, uint c)
Sets the counter used to advance to the next clear density/field type.
Definition clear_map.h:132
uint GetFence(Tile t, DiagDirection side)
Is there a fence at the given border?
Definition clear_map.h:209
bool IsSnowTile(Tile t)
Test if a tile is covered with snow.
Definition clear_map.h:35
CommandCost CommandCostWithParam(StringID str, uint64_t value)
Return an error status, with string and parameter.
Definition command.cpp:417
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ 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.
static uint ScaleByInverseCargoScale(uint num, bool town)
Scale a number by the inverse of the cargo scale setting, e.g.
bool EconomyIsInRecession()
Is the economy in recession?
uint ScaleByCargoScale(uint num, bool town)
Scale a number by the cargo scale setting.
@ EXPENSES_CONSTRUCTION
Construction costs.
@ EXPENSES_OTHER
Other expenses.
EffectVehicle * CreateEffectVehicle(int x, int y, int z, EffectVehicleType type)
Create an effect vehicle at a particular location.
EffectVehicle * CreateEffectVehicleAbove(int x, int y, int z, EffectVehicleType type)
Create an effect vehicle above a particular location.
Base class for all effect vehicles.
Functions related to effect vehicles.
@ EV_BUBBLE
Bubble of bubble generator (industry).
@ EV_CHIMNEY_SMOKE
Smoke of power plant (industry).
@ EV_COPPER_MINE_SMOKE
Smoke at copper mine.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
Functions related to errors.
@ WL_WARNING
Other information.
Definition error.h:25
@ WL_INFO
Used for DoCommand-like (and some non-fatal AI GUI) errors/information.
Definition error.h:24
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, CommandCost &cc)
Display an error message in a window.
Base functions for all Games.
bool _generating_world
Whether we are generating the map or not.
Definition genworld.cpp:74
Functions related to world/map generation.
void IncreaseGeneratingWorldProgress(GenWorldProgress cls)
Increases the current stage of the world generation with one.
@ LG_TERRAGENESIS
TerraGenesis Perlin landscape generator.
Definition genworld.h:22
@ GWP_LAND_INDUSTRY
Generate industries.
Definition genworld.h:67
@ GWP_WATER_INDUSTRY
Generate industries.
Definition genworld.h:68
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.
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
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.
@ NoClosure
Industry can not close regardless of production level or time since last delivery.
@ NoProductionDecrease
When industry production change is evaluated, rolls to decrease are ignored.
@ NoProductionIncrease
When industry production change is evaluated, rolls to increase are ignored.
static uint16_t GetIndustryGamePlayProbability(IndustryType it, uint8_t *min_number)
Compute the probability for constructing a new industry during game play.
static CommandCost CheckNewIndustry_Water(TileIndex tile)
Check the conditions of CHECK_WATER (Industry should be in the desert).
static 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.
bool IsTileForestIndustry(TileIndex tile)
Check whether the tile is a forest.
const IndustryTileSpec * GetIndustryTileSpec(IndustryGfx gfx)
Accessor for array _industry_tile_specs.
static void CanCargoServiceIndustry(CargoType cargo, Industry *ind, bool *c_accepts, bool *c_produces)
Can given cargo type be accepted or produced by the industry?
void GenerateIndustries()
This function will create random industries during game creation.
static void ProduceIndustryGoodsHelper(Industry *i, bool scale)
Helper for ProduceIndustryGoods that scales and produces cargos.
IndustryBuildData _industry_builder
In-game manager of industries.
static Industry * PlaceIndustry(IndustryType type, IndustryAvailabilityCallType creation_type, bool try_hard)
Try to place the industry in the game.
static const IntervalTimer< TimerGameEconomy > _economy_industries_daily({TimerGameEconomy::DAY, TimerGameEconomy::Priority::INDUSTRY}, [](auto) { _economy.industry_daily_change_counter+=_economy.industry_daily_increment;uint16_t change_loop=_economy.industry_daily_change_counter > > 16;_economy.industry_daily_change_counter &=0xFFFF;if(change_loop==0) { return;} Backup< CompanyID > cur_company(_current_company, OWNER_NONE);uint perc=3;if((_industry_builder.wanted_inds > > 16) > GetCurrentTotalNumberOfIndustries()) { perc=std::min(9u, perc+(_industry_builder.wanted_inds > > 16) - GetCurrentTotalNumberOfIndustries());} for(uint16_t j=0;j< change_loop;j++) { if(Chance16(perc, 100)) { _industry_builder.TryBuildNewIndustry();} else { Industry *i=Industry::GetRandom();if(i !=nullptr) { ChangeIndustryProduction(i, false);SetWindowDirty(WC_INDUSTRY_VIEW, i->index);} } } cur_company.Restore();InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, IDIWD_PRODUCTION_CHANGE);})
Every economy day handler for the industry changes Taking the original map size of 256*256,...
static CommandCost CheckNewIndustry_Plantation(TileIndex tile)
Check the conditions of CHECK_PLANTATION (Industry should NOT be in the desert).
void CheckIndustries()
Verify whether the generated industries are complete, and warn the user if not.
static void PopulateStationsNearby(Industry *ind)
Populate an industry's list of nearby stations, and if it accepts any cargo, also add the industry to...
static CommandCost CheckNewIndustry_Forest(TileIndex tile)
Check the conditions of CHECK_FOREST (Industry should be build above snow-line in arctic climate).
static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, const IndustryTileLayout &layout, size_t layout_index, Town *t, Owner founder, uint16_t initial_random_bits)
Put an industry on the map.
CommandCost CheckNewIndustryProc(TileIndex tile)
Industrytype check function signature.
static CommandCost CreateNewIndustryHelper(TileIndex tile, IndustryType type, DoCommandFlags flags, const IndustrySpec *indspec, size_t layout_index, uint32_t random_var8f, uint16_t random_initial_bits, Owner founder, IndustryAvailabilityCallType creation_type, Industry **ip)
Helper function for Build/Fund an industry.
static int WhoCanServiceIndustry(Industry *ind)
Compute who can service the industry.
void ResetIndustries()
This function initialize the spec arrays of both industry and industry tiles.
static CommandCost CheckIfFarEnoughFromConflictingIndustry(TileIndex tile, IndustryType type)
Check that the new industry is far enough from conflicting industries.
static bool IsSuitableForFarmField(TileIndex tile, bool allow_fields)
Check whether the tile can be replaced by a farm field.
static CommandCost CheckNewIndustry_OilRig(TileIndex tile)
Check the conditions of CHECK_OIL_RIG (Industries at sea should be positioned near edge of the map).
void TrimIndustryAcceptedProduced(Industry *ind)
Remove unused industry accepted/produced slots – entries after the last slot with valid cargo.
static uint GetNumberOfIndustries()
Get wanted number of industries on the map.
CommandCost CmdBuildIndustry(DoCommandFlags flags, TileIndex tile, IndustryType it, uint32_t first_layout, bool fund, uint32_t seed)
Build/Fund an industry.
static 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 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 DrawIndustryCoordinates _coal_plant_sparks[]
Movement of the sparks , only used for Power Station.
static const DrawBuildingsTileStruct _industry_draw_tile_data[NEW_INDUSTRYTILEOFFSET *4]
Structure for industry tiles drawing.
void SetIndustryCompleted(Tile tile)
Set if the industry that owns the tile as under construction or not.
void SetIndustryGfx(Tile t, IndustryGfx gfx)
Set the industry graphics ID for the given industry tile.
void ResetIndustryConstructionStage(Tile tile)
Reset the construction stage counter of the industry, as well as the completion bit.
void SetIndustryConstructionCounter(Tile tile, uint8_t value)
Sets this industry tile's construction counter value.
IndustryGfx GetIndustryGfx(Tile t)
Get the industry graphics ID for the given industry tile.
bool IsIndustryCompleted(Tile t)
Is this industry tile fully built?
IndustryID GetIndustryIndex(Tile t)
Get the industry ID of the given tile.
uint8_t GetIndustryConstructionCounter(Tile tile)
Returns this industry tile's construction counter value.
void MakeIndustry(Tile t, IndustryID index, IndustryGfx gfx, uint8_t random, WaterClass wc)
Make the given tile an industry tile.
void SetIndustryAnimationLoop(Tile tile, uint8_t count)
Set the animation loop number.
@ GFX_WATERTILE_SPECIALCHECK
not really a tile, but rather a very special check
void SetIndustryConstructionStage(Tile tile, uint8_t value)
Sets the industry construction stage of the specified tile.
uint8_t GetIndustryAnimationLoop(Tile tile)
Get the animation loop number.
uint8_t GetIndustryConstructionStage(Tile tile)
Returns the industry construction stage of the specified tile.
static const IndustryGfx NEW_INDUSTRYTILEOFFSET
original number of tiles
static const IndustryGfx INDUSTRYTILE_NOANIM
flag to mark industry tiles as having no animation
@ 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.).
@ Random
Randomise borders.
uint DistanceMax(TileIndex t0, TileIndex t1)
Gets the biggest distance component (x or y) between the two given tiles.
Definition map.cpp:190
uint DistanceFromEdgeDir(TileIndex tile, DiagDirection dir)
Gets the distance to the edge of the map in given direction.
Definition map.cpp:235
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:109
Functions related to maps.
TileIndex TileAddXY(TileIndex tile, int x, int y)
Adds a given offset to a tile.
Definition map_func.h:482
TileIndexDiff ToTileIndexDiff(TileIndexDiffC tidc)
Return the offset between two tiles from a TileIndexDiffC struct.
Definition map_func.h:452
TileIndexDiff TileDiffXY(int x, int y)
Calculates an offset for the given coordinate(-offset).
Definition map_func.h:401
TileIndexDiff TileOffsByAxis(Axis axis)
Convert an Axis to a TileIndexDiff.
Definition map_func.h:567
#define RandomTile()
Get a valid random tile.
Definition map_func.h:664
static debug_inline uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:437
static debug_inline uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:427
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition map_func.h:582
int32_t TileIndexDiff
An offset value between two tiles.
Definition map_type.h:23
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition math_func.hpp:23
constexpr uint CeilDiv(uint a, uint b)
Computes ceil(a / b) for non-negative a and b.
constexpr T Delta(const T a, const T b)
Returns the (absolute) difference between two (scalar) variables.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
constexpr uint ClampU(const uint a, const uint min, const uint max)
Clamp an unsigned integer between an interval.
StringID MapGRFStringID(uint32_t grfid, GRFStringID str)
Used when setting an object's property to map to the GRF's strings while taking in consideration the ...
@ 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.
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.
@ IndustryClose
Closing of industries.
@ IndustryOpen
Opening of industries.
@ IndustryNobody
Other industry production changes.
@ IndustryOther
Production changes of industry serviced by competitor(s)
Base for all objects.
@ OUFB_TRANSFER
Transfer all cargo onto the platform.
Definition order_type.h:70
@ OUFB_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
@ ID_CUSTOM
Custom number of industries.
@ ID_VERY_LOW
Very few industries at game start.
@ ID_END
Number of industry density settings.
@ ID_FUND_ONLY
The game does not build industries.
static constexpr int GetSlopeMaxZ(Slope s)
Returns the height of the highest corner of a slope relative to TileZ (= minimal height)
Definition slope_func.h:160
static constexpr bool IsSteepSlope(Slope s)
Checks if a slope is steep.
Definition slope_func.h:36
Foundation FlatteningFoundation(Slope s)
Returns the foundation needed to flatten a slope.
Definition slope_func.h:369
Slope ComplementSlope(Slope s)
Return the complement of a slope.
Definition slope_func.h:76
Slope
Enumeration for the slope-type.
Definition slope_type.h:48
@ SLOPE_W
the west corner of the tile is raised
Definition slope_type.h:50
@ SLOPE_E
the east corner of the tile is raised
Definition slope_type.h:52
@ SLOPE_S
the south corner of the tile is raised
Definition slope_type.h:51
@ SLOPE_N
the north corner of the tile is raised
Definition slope_type.h:53
@ SLOPE_SW
south and west corner are raised
Definition slope_type.h:56
@ SLOPE_FLAT
a flat tile
Definition slope_type.h:49
@ SLOPE_NE
north and east corner are raised
Definition slope_type.h:58
@ SLOPE_SE
south and east corner are raised
Definition slope_type.h:57
@ SLOPE_NW
north and west corner are raised
Definition slope_type.h:55
Foundation
Enumeration for Foundations.
Definition slope_type.h:93
@ FOUNDATION_LEVELED
The tile is leveled up to a flat slope.
Definition slope_type.h:95
@ FOUNDATION_NONE
The tile has no foundation, the slope remains unchanged.
Definition slope_type.h:94
Functions related to sound.
SoundFx
Sound effects from baseset.
Definition sound_type.h:45
@ SND_30_TOFFEE_QUARRY
48 == 0x30 Industry animation: toffee quarry: drill
Definition sound_type.h:95
@ SND_2E_BUBBLE_GENERATOR
46 == 0x2E Industry animation: bubble generator (1): generate bubble
Definition sound_type.h:93
@ SND_2D_SUGAR_MINE_1
45 == 0x2D Industry animation: sugar mine (1): shaking sieve
Definition sound_type.h:92
@ SND_2B_TOY_FACTORY_2
43 == 0x2B Industry animation: toy factory (2): stamp product
Definition sound_type.h:90
@ SND_38_LUMBER_MILL_1
56 == 0x38 Industry animation: lumber mill (1): chainsaw
Definition sound_type.h:103
@ SND_29_SUGAR_MINE_2
41 == 0x29 Industry animation: sugar mine (2): shaking sieve
Definition sound_type.h:88
@ SND_2C_TOY_FACTORY_1
44 == 0x2C Industry animation: toy factory (1): conveyor belt
Definition sound_type.h:91
@ SND_37_LUMBER_MILL_2
55 == 0x37 Industry animation: lumber mill (2): falling tree
Definition sound_type.h:102
@ SND_0C_POWER_STATION
10 == 0x0A Industry animation: power station: spark
Definition sound_type.h:57
@ SND_0B_MINE
9 == 0x09 Industry animation: coal/copper/gold mine: headgear
Definition sound_type.h:56
@ SND_36_LUMBER_MILL_3
54 == 0x36 Industry animation: lumber mill (3): crashing tree
Definition sound_type.h:101
@ SND_2A_TOY_FACTORY_3
42 == 0x2A Industry animation: toy factory (3): eject product
Definition sound_type.h:89
@ Industry
Source/destination is an industry.
static PaletteID GetColourPalette(Colours colour)
Get recolour palette for a colour.
Definition sprite.h:188
PaletteID SpriteLayoutPaletteTransform(SpriteID image, PaletteID pal, PaletteID default_pal)
Applies PALETTE_MODIFIER_TRANSPARENT and PALETTE_MODIFIER_COLOUR to a palette entry of a sprite layou...
Definition sprite.h:155
PaletteID GroundSpritePaletteTransform(SpriteID image, PaletteID pal, PaletteID default_pal)
Applies PALETTE_MODIFIER_COLOUR to a palette entry of a ground sprite.
Definition sprite.h:174
Base classes/functions for stations.
void ForAllStationsAroundTiles(const TileArea &ta, Func func)
Call a function on all stations that have any part of the requested area within their catchment.
void ClearDockingTilesCheckingNeighbours(TileIndex tile)
Clear docking tile status from tiles around a removed dock, if the tile has no neighbours which would...
bool IsOilRig(Tile t)
Is tile t part of an oilrig?
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:271
Functions related to low-level strings.
void GetStringWithArgs(StringBuilder &builder, StringID string, StringParameters &args, uint case_index, bool game_script)
Get a parsed string with most special stringcodes replaced by the string parameters.
Definition strings.cpp:336
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp: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:113
static void InvalidateAllFrom(Source src)
Invalidates (sets source_id to INVALID_SOURCE) all cargo packets from given source.
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:137
StringID name
Name of this type of cargo.
Definition cargotype.h:91
bool value
tells if the bool cheat is active or not
Definition cheat_type.h:18
Cheat magic_bulldozer
dynamite industries, objects
Definition cheat_type.h:27
SoundSettings sound
sound effect settings
uint8_t raw_industry_construction
type of (raw) industry construction (none, "normal", prospecting)
uint8_t industry_platform
the amount of flat land around an industry
uint8_t industry_density
The industry density.
This structure is the same for both Industries and Houses.
Definition sprite.h:81
This is used to gather some data about animation drawing in the industry code Image_1-2-3 are in fact...
uint8_t image_1
image offset 1
uint8_t image_3
image offset 3
uint8_t image_2
image offset 2
int x
coordinate x of the first image offset
EconomyType type
economy type (original/smooth/frozen)
bool multiple_industry_per_town
allow many industries of the same type per town
uint32_t industry_daily_change_counter
Bits 31-16 are number of industry to be performed, 15-0 are fractional collected daily.
uint32_t industry_daily_increment
The value which will increment industry_daily_change_counter. Computed value. NOSAVE.
A special vehicle is one of the following:
uint8_t animation_substate
Sub state to time the change of the graphics/behaviour.
std::string GetName() const
Get the name of this grf.
const struct GRFFile * grffile
grf file that introduced this entity
uint32_t grfid
grfid that introduced this entity.
bool HasGrfFile() const
Test if this entity was introduced by NewGRF.
uint16_t custom_industry_number
manually entered number of industries
LandscapeType landscape
the landscape we're currently in
uint8_t oil_refinery_limit
distance oil refineries allowed from map edge
uint8_t land_generator
the landscape generator
EconomySettings economy
settings to change the economy
ConstructionSettings construction
construction of things in-game
DifficultySettings difficulty
settings related to the difficulty
GameCreationSettings game_creation
settings used during the creation of a game (map)
StationSettings station
settings related to station management
Data for managing the number and type of industries in the game.
Definition industry.h:306
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:308
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:307
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.
uint8_t cost_multiplier
Base construction cost multiplier.
bool IsRawIndustry() const
Is an industry with the spec a raw industry?
IndustryType conflicting[3]
Industries this industry cannot be close to.
uint8_t appear_ingame[NUM_LANDSCAPE]
Probability of appearance in game.
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:291
uint32_t probability
Relative probability of building this industry.
Definition industry.h:292
uint16_t target_count
Desired number of industries of this type.
Definition industry.h:294
uint8_t min_number
Smallest number of industries that should exist (either 0 or 1).
Definition industry.h:293
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:296
uint16_t max_wait
Starting number of turns to wait (copied to wait_count).
Definition industry.h:295
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:264
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
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:276
static TileIndex WrapToMap(TileIndex tile)
'Wraps' the given "tile" so it is within the map.
Definition map_func.h:329
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:340
static uint SizeY()
Get the size of the map along the Y.
Definition map_func.h:281
static debug_inline uint SizeX()
Get the size of the map along the X.
Definition map_func.h:272
static uint ScaleByLandProportion(uint n)
Scales the given value by the number of water tiles.
Definition map_func.h:318
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:353
static uint MaxY()
Gets the maximum Y coordinate within the map, including MP_VOID.
Definition map_func.h:308
static debug_inline uint Size()
Get the size of the map.
Definition map_func.h:290
static debug_inline uint MaxX()
Gets the maximum X coordinate within the map, including MP_VOID.
Definition map_func.h:299
Represents the covered area of e.g.
void ClampToMap()
Clamp the tile area to map borders.
Definition tilearea.cpp:142
uint16_t w
The width of the area.
void Add(TileIndex to_add)
Add a single tile to a tile area; enlarge if needed.
Definition tilearea.cpp:43
TileIndex tile
The base tile of the area.
uint16_t h
The height of the area.
OrthogonalTileArea & Expand(int rad)
Expand a tile area by rad tiles in each direction, keeping within map bounds.
Definition tilearea.cpp:123
SpriteID sprite
The 'real' sprite.
Definition gfx_type.h:23
PaletteID pal
The palette (use PAL_NONE) if not needed)
Definition gfx_type.h:24
Templated helper to make a PoolID a single POD value.
Definition pool_type.hpp:43
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static size_t GetPoolSize()
Returns first unused index.
static Titem * Get(auto index)
Returns Titem with given index.
static size_t GetNumItems()
Returns number of valid items in the pool.
Tindex index
Index of this pool item.
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
static bool CleaningPool()
Returns current state of pool cleaning - yes or no.
static Titem * GetIfValid(auto index)
Returns Titem with given index.
Base class for all pools.
static constexpr size_t MAX_SIZE
Make template parameter accessible from outside.
Structure to encapsulate the pseudo random number generators.
void SetSeed(uint32_t seed)
(Re)set the state of the random number generator.
uint32_t Next()
Generate the next pseudo random number.
bool ambient
Play ambient, industry and town sounds.
A location from where cargo can come from (or go to).
Definition source_type.h:32
static Station * Get(auto index)
Gets station with given index.
T * Next() const
Get next vehicle in the chain.
bool HasSpriteGroups() const
Check whether the entity has sprite groups.
bool serve_neutral_industries
company stations can serve industries with attached neutral stations
Station data structure.
IndustryList industries_near
Cached list of industries near the station that can accept cargo,.
Tile description for the 'land area information' tool.
Definition tile_cmd.h:36
std::optional< std::string > grf
newGRF used for the tile contents
Definition tile_cmd.h:47
StringID str
Description of the tile.
Definition tile_cmd.h:37
std::array< Owner, 4 > owner
Name of the owner(s)
Definition tile_cmd.h:39
uint64_t dparam
Parameter of the str string.
Definition tile_cmd.h:38
Tile information, used while rendering the tile.
Definition tile_cmd.h:30
Slope tileh
Slope of the tile.
Definition tile_cmd.h:31
TileIndex tile
Tile index.
Definition tile_cmd.h:32
Set of callback functions for performing tile operations of a given tile type.
Definition tile_cmd.h:152
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
debug_inline 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:95
int GetTileMaxZ(TileIndex t)
Get top height of the tile inside the map.
Definition tile_map.cpp:136
int GetTileZ(TileIndex tile)
Get bottom height of the tile.
Definition tile_map.cpp:116
int GetTileMaxPixelZ(TileIndex tile)
Get top height of the tile.
Definition tile_map.h:312
static debug_inline TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition tile_map.h:96
uint8_t GetAnimationFrame(Tile t)
Get the current animation frame.
Definition tile_map.h:250
bool IsValidTile(Tile tile)
Checks if a tile is valid.
Definition tile_map.h:161
TropicZone GetTropicZone(Tile tile)
Get the tropic zone.
Definition tile_map.h:238
void SetAnimationFrame(Tile t, uint8_t frame)
Set a new animation frame.
Definition tile_map.h:262
static debug_inline bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
Slope GetTileSlope(TileIndex tile)
Return the slope of a given tile inside the map.
Definition tile_map.h:279
static debug_inline uint TileHeight(Tile tile)
Returns the height of a tile.
Definition tile_map.h:29
@ TROPICZONE_RAINFOREST
Rainforest tile.
Definition tile_type.h:79
@ TROPICZONE_DESERT
Tile is desert.
Definition tile_type.h:78
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
static constexpr uint TILE_SIZE
Tile size in world coordinates.
Definition tile_type.h:15
@ MP_TREES
Tile got trees.
Definition tile_type.h:52
@ MP_STATION
A tile of a station.
Definition tile_type.h:53
@ MP_CLEAR
A tile without any structures, i.e. grass, rocks, farm fields etc.
Definition tile_type.h:48
@ MP_HOUSE
A house by a town.
Definition tile_type.h:51
@ MP_INDUSTRY
Part of an industry.
Definition tile_type.h:56
@ MP_VOID
Invisible tiles at the SW and SE border.
Definition tile_type.h:55
OrthogonalTileArea TileArea
Shorthand for the much more common orthogonal tile area.
Definition of Interval and OneShot timers.
Definition of the game-calendar-timer.
Definition of the game-economy-timer.
Definition of the tick-based game-timer.
Base of the town class.
Town * ClosestTownFromTile(TileIndex tile, uint threshold)
Return the town closest (in distance or ownership) to a given tile, within a given threshold.
bool IsTransparencySet(TransparencyOption to)
Check if the transparency option bit is set and if we aren't in the game menu (there's never transpar...
bool IsInvisibilitySet(TransparencyOption to)
Check if the invisibility option bit is set and if we aren't in the game menu (there's never transpar...
@ TO_INDUSTRIES
industries
TransportType
Available types of transport.
Map accessors for tree tiles.
TreeGrowthStage GetTreeGrowth(Tile t)
Returns the tree growth stage.
Definition tree_map.h:195
TreeGround GetTreeGround(Tile t)
Returns the groundtype for tree tiles.
Definition tree_map.h:102
@ TREE_GROUND_SHORE
shore
Definition tree_map.h:56
@ Grown
Fully grown tree.
CommandCost EnsureNoVehicleOnGround(TileIndex tile)
Ensure there is no vehicle at the ground at the given position.
Definition vehicle.cpp:527
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:663
void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool transparent, const SubSprite *sub, bool scale, bool relative)
Add a child sprite to a parent sprite.
Definition viewport.cpp:824
void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub, int extra_offs_x, int extra_offs_y)
Draws a ground sprite for the current tile.
Definition viewport.cpp:579
Functions related to (drawing on) viewports.
Functions related to water (management)
void TileLoop_Water(TileIndex tile)
Let a water tile floods its diagonal adjoining tiles called from tunnelbridge_cmd,...
bool IsTileOnWater(Tile t)
Tests if the tile was built on water.
Definition water_map.h: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).
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:1193
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:3294
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3176
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: