OpenTTD Source 20260731-master-g77ba2b244a
industry_cmd.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "stdafx.h"
11#include "misc/history_type.hpp"
12#include "misc/history_func.hpp"
13#include "clear_map.h"
14#include "industry.h"
15#include "station_base.h"
16#include "landscape.h"
17#include "viewport_func.h"
18#include "command_func.h"
19#include "town.h"
20#include "news_func.h"
21#include "cheat_type.h"
22#include "company_base.h"
23#include "genworld.h"
24#include "tree_map.h"
25#include "newgrf_cargo.h"
26#include "newgrf_debug.h"
28#include "autoslope.h"
29#include "water.h"
30#include "strings_func.h"
31#include "window_func.h"
32#include "vehicle_func.h"
33#include "sound_func.h"
34#include "animated_tile_func.h"
35#include "effectvehicle_func.h"
36#include "effectvehicle_base.h"
37#include "ai/ai.hpp"
38#include "core/pool_func.hpp"
39#include "subsidy_func.h"
40#include "core/backup_type.hpp"
41#include "object_base.h"
42#include "game/game.hpp"
43#include "error.h"
44#include "string_func.h"
45#include "industry_cmd.h"
46#include "landscape_cmd.h"
47#include "terraform_cmd.h"
48#include "map_func.h"
49#include "script/api/script_event_types.hpp"
50#include "timer/timer.h"
54
55#include "table/strings.h"
56#include "table/industry_land.h"
58
59#include "safeguards.h"
60
61IndustryPool _industry_pool("Industry");
63
64void ShowIndustryViewWindow(IndustryID industry);
65void BuildOilRig(TileIndex tile);
66
67static uint8_t _industry_sound_ctr;
68static TileIndex _industry_sound_tile;
69
70std::array<FlatSet<IndustryID>, NUM_INDUSTRYTYPES> Industry::industries;
71
72IndustrySpec _industry_specs[NUM_INDUSTRYTYPES];
73IndustryTileSpec _industry_tile_specs[NUM_INDUSTRYTILES];
75
76static int WhoCanServiceIndustry(Industry *ind);
77
85{
86 auto industry_insert = std::copy(std::begin(_origin_industry_specs), std::end(_origin_industry_specs), std::begin(_industry_specs));
87 std::fill(industry_insert, std::end(_industry_specs), IndustrySpec{});
88
89 /* Enable only the current climate industries */
90 for (auto it = std::begin(_industry_specs); it != industry_insert; ++it) {
91 it->enabled = it->climate_availability.Test(_settings_game.game_creation.landscape);
92 }
93
94 auto industry_tile_insert = std::copy(std::begin(_origin_industry_tile_specs), std::end(_origin_industry_tile_specs), std::begin(_industry_tile_specs));
95 std::fill(industry_tile_insert, std::end(_industry_tile_specs), IndustryTileSpec{});
96
97 /* Reset any overrides that have been set. */
98 _industile_mngr.ResetOverride();
99 _industry_mngr.ResetOverride();
100}
101
110IndustryType GetIndustryType(Tile tile)
111{
112 assert(IsTileType(tile, TileType::Industry));
113
114 const Industry *ind = Industry::GetByTile(tile);
115 assert(ind != nullptr);
116 return ind->type;
117}
118
127const IndustrySpec *GetIndustrySpec(IndustryType thistype)
128{
129 assert(thistype < NUM_INDUSTRYTYPES);
130 return &_industry_specs[thistype];
131}
132
142{
143 assert(gfx < NUM_INDUSTRYTILES);
144 return &_industry_tile_specs[gfx];
145}
146
149{
150 if (CleaningPool()) return;
151
152 /* Industry can also be destroyed when not fully initialized.
153 * This means that we do not have to clear tiles either.
154 * Also we must not decrement industry counts in that case. */
155 if (this->location.w == 0) return;
156
157 const bool has_neutral_station = this->neutral_station != nullptr;
158
159 for (TileIndex tile_cur : this->location) {
160 if (IsTileType(tile_cur, TileType::Industry)) {
161 if (GetIndustryIndex(tile_cur) == this->index) {
163
164 /* MakeWaterKeepingClass() can also handle 'land' */
165 MakeWaterKeepingClass(tile_cur, OWNER_NONE);
166 }
167 } else if (IsTileType(tile_cur, TileType::Station) && IsOilRig(tile_cur)) {
168 DeleteOilRig(tile_cur);
169 }
170 }
171
172 if (has_neutral_station) {
173 /* Remove possible docking tiles */
174 for (TileIndex tile_cur : this->location) {
176 }
177 }
178
179 if (GetIndustrySpec(this->type)->behaviour.Test(IndustryBehaviour::PlantFields)) {
180 TileArea ta = TileArea(this->location.tile, 0, 0).Expand(21);
181
182 /* Remove the farmland and convert it to regular tiles over time. */
183 for (TileIndex tile_cur : ta) {
184 if (IsTileType(tile_cur, TileType::Clear) && IsClearGround(tile_cur, ClearGround::Fields) &&
185 GetIndustryIndexOfField(tile_cur) == this->index) {
186 SetIndustryIndexOfField(tile_cur, IndustryID::Invalid());
187 }
188 }
189 }
190
191 /* don't let any disaster vehicle target invalid industry */
193
194 /* Clear the persistent storage. */
195 delete this->psa;
196
198 industries.erase(this->index);
199
201 CloseWindowById(WindowClass::IndustryView, this->index);
202 CloseWindowById(WindowClass::IndustryProductionGraph, this->index);
204
208
209 for (Station *st : this->stations_near) {
210 st->RemoveIndustryToDeliver(this);
211 }
212}
213
219{
220 InvalidateWindowData(WindowClass::IndustryDirectory, 0, IDIWD_FORCE_REBUILD);
221 SetWindowDirty(WindowClass::BuildIndustry, 0);
222}
223
224
229/* static */ Industry *Industry::GetRandom()
230{
231 if (Industry::GetNumItems() == 0) return nullptr;
232 int num = RandomRange((uint16_t)Industry::GetNumItems());
233 size_t index = std::numeric_limits<size_t>::max();
234
235 while (num >= 0) {
236 num--;
237 index++;
238
239 /* Make sure we have a valid industry */
240 while (!Industry::IsValidID(index)) {
241 index++;
242 assert(index < Industry::GetPoolSize());
243 }
244 }
245
246 return Industry::Get(index);
247}
248
249
250static void IndustryDrawSugarMine(const TileInfo *ti)
251{
252 if (!IsIndustryCompleted(ti->tile)) return;
253
255
257
258 if (d->image_2 != 0) {
259 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_CLOUDS + d->image_2 - 1, PAL_NONE, 8, 41);
260 }
261
262 if (d->image_3 != 0) {
264 _drawtile_proc1[d->image_3 - 1].x, _drawtile_proc1[d->image_3 - 1].y);
265 }
266}
267
268static void IndustryDrawToffeeQuarry(const TileInfo *ti)
269{
270 uint8_t x = 0;
271
272 if (IsIndustryCompleted(ti->tile)) {
274 if (x == 0xFF) {
275 x = 0;
276 }
277 }
278
279 AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_SHOVEL, PAL_NONE, 22 - x, 24 + x);
281}
282
283static void IndustryDrawBubbleGenerator( const TileInfo *ti)
284{
285 if (IsIndustryCompleted(ti->tile)) {
287 }
289}
290
291static void IndustryDrawToyFactory(const TileInfo *ti)
292{
293 const DrawIndustryAnimationStruct *d = &_industry_anim_offs_toys[GetAnimationFrame(ti->tile)];
294
295 if (d->image_1 != 0xFF) {
297 }
298
299 if (d->image_2 != 0xFF) {
300 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_ROBOT, PAL_NONE, 16 - d->image_2 * 2, 100 + d->image_2);
301 }
302
305}
306
307static void IndustryDrawCoalPlantSparks(const TileInfo *ti)
308{
309 if (IsIndustryCompleted(ti->tile)) {
310 uint8_t image = GetAnimationFrame(ti->tile);
311
312 if (image != 0 && image < 7) {
314 PAL_NONE,
315 _coal_plant_sparks[image - 1].x,
316 _coal_plant_sparks[image - 1].y
317 );
318 }
319 }
320}
321
322typedef void IndustryDrawTileProc(const TileInfo *ti);
323static IndustryDrawTileProc * const _industry_draw_tile_procs[5] = {
324 IndustryDrawSugarMine,
325 IndustryDrawToffeeQuarry,
326 IndustryDrawBubbleGenerator,
327 IndustryDrawToyFactory,
328 IndustryDrawCoalPlantSparks,
329};
330
333{
334 IndustryGfx gfx = GetIndustryGfx(ti->tile);
336 const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
337
338 /* Retrieve pointer to the draw industry tile struct */
339 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
340 /* Draw the tile using the specialized method of newgrf industrytile.
341 * DrawNewIndustry will return false if ever the resolver could not
342 * find any sprite to display. So in this case, we will jump on the
343 * substitute gfx instead. */
344 if (indts->grf_prop.HasSpriteGroups() && DrawNewIndustryTile(ti, ind, gfx, indts)) {
345 return;
346 } else {
347 /* No sprite group (or no valid one) found, meaning no graphics associated.
348 * Use the substitute one instead */
349 if (indts->grf_prop.subst_id != INVALID_INDUSTRYTILE) {
350 gfx = indts->grf_prop.subst_id;
351 /* And point the industrytile spec accordingly */
352 indts = GetIndustryTileSpec(gfx);
353 }
354 }
355 }
356
357 const DrawBuildingsTileStruct *dits = &_industry_draw_tile_data[gfx << 2 | (indts->anim_state ?
360
361 SpriteID image = dits->ground.sprite;
362
363 /* DrawFoundation() modifies ti->z and ti->tileh */
365
366 /* If the ground sprite is the default flat water sprite, draw also canal/river borders.
367 * Do not do this if the tile's WaterClass is 'land'. */
368 if (image == SPR_FLAT_WATER_TILE && IsTileOnWater(ti->tile)) {
369 DrawWaterClassGround(ti);
370 } else {
372 }
373
374 /* If industries are transparent and invisible, do not draw the upper part */
376
377 /* Add industry on top of the ground? */
378 image = dits->building.sprite;
379 if (image != 0) {
382
384 }
385
386 {
387 int proc = dits->draw_proc - 1;
388 if (proc >= 0) _industry_draw_tile_procs[proc](ti);
389 }
390}
391
394{
395 IndustryGfx gfx = GetIndustryGfx(tile);
396
397 /* For NewGRF industry tiles we might not be drawing a foundation. We need to
398 * account for this, as other structures should
399 * draw the wall of the foundation in this case.
400 */
401 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
402 const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
404 uint32_t callback_res = GetIndustryTileCallback(CBID_INDTILE_DRAW_FOUNDATIONS, 0, 0, gfx, Industry::GetByTile(tile), tile);
405 if (callback_res != CALLBACK_FAILED && !ConvertBooleanCallback(indts->grf_prop.grffile, CBID_INDTILE_DRAW_FOUNDATIONS, callback_res)) return Foundation::None;
406 }
407 }
408 return FlatteningFoundation(tileh);
409}
410
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 (always_accepted.Test(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 always_accepted.Set(cargo);
469 }
470}
471
474{
475 const Industry *i = Industry::GetByTile(tile);
476 const IndustrySpec *is = GetIndustrySpec(i->type);
477
478 td.owner[0] = i->owner;
479 td.str = is->name;
480 if (!IsIndustryCompleted(tile)) {
481 td.dparam = td.str.base();
482 td.str = STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION;
483 }
484
485 if (is->grf_prop.HasGrfFile()) {
487 }
488}
489
492{
493 Industry *i = Industry::GetByTile(tile);
494 const IndustrySpec *indspec = GetIndustrySpec(i->type);
495
496 /* water can destroy industries
497 * in editor you can bulldoze industries
498 * with magic_bulldozer cheat you can destroy industries
499 * (area around OILRIG is water, so water shouldn't flood it
500 */
501 if ((_current_company != OWNER_WATER && _game_mode != GameMode::Editor &&
502 !_cheats.magic_bulldozer.value) ||
503 flags.Test(DoCommandFlag::Auto) ||
506 HasBit(GetIndustryTileSpec(GetIndustryGfx(tile))->slopes_refused, 5)))) {
507
508 if (flags.Test(DoCommandFlag::Auto)) {
509 return CommandCostWithParam(STR_ERROR_GENERIC_OBJECT_IN_THE_WAY, indspec->name);
510 }
512 }
513
514 if (flags.Test(DoCommandFlag::Execute)) {
515 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index));
516 Game::NewEvent(new ScriptEventIndustryClose(i->index));
517 delete i;
518 }
520}
521
528{
529 Industry *i = Industry::GetByTile(tile);
530 const IndustrySpec *indspec = GetIndustrySpec(i->type);
531 bool moved_cargo = false;
532
533 for (auto &p : i->produced) {
534 uint cw = ClampTo<uint8_t>(p.waiting);
535 if (cw > indspec->minimal_cargo && IsValidCargoType(p.cargo)) {
536 p.waiting -= cw;
537
538 /* fluctuating economy? */
539 if (EconomyIsInRecession()) cw = (cw + 1) / 2;
540
541 p.history[THIS_MONTH].production += cw;
542
543 uint am = MoveGoodsToStation(p.cargo, cw, {i->index, SourceType::Industry}, i->stations_near, i->exclusive_consumer);
544 p.history[THIS_MONTH].transported += am;
545
546 moved_cargo |= (am != 0);
547 }
548 }
549
550 return moved_cargo;
551}
552
553static void AnimateSugarSieve(TileIndex tile)
554{
555 uint8_t m = GetAnimationFrame(tile) + 1;
556
557 if (_settings_client.sound.ambient) {
558 switch (m & 7) {
559 case 2: SndPlayTileFx(SND_2D_SUGAR_MINE_1, tile); break;
560 case 6: SndPlayTileFx(SND_29_SUGAR_MINE_2, tile); break;
561 }
562 }
563
564 if (m >= 96) {
565 m = 0;
566 DeleteAnimatedTile(tile);
567 }
568 SetAnimationFrame(tile, m);
569
571}
572
573static void AnimateToffeeQuarry(TileIndex tile)
574{
575 uint8_t m = GetAnimationFrame(tile);
576
577 if (_industry_anim_offs_toffee[m] == 0xFF && _settings_client.sound.ambient) {
578 SndPlayTileFx(SND_30_TOFFEE_QUARRY, tile);
579 }
580
581 if (++m >= 70) {
582 m = 0;
583 DeleteAnimatedTile(tile);
584 }
585 SetAnimationFrame(tile, m);
586
588}
589
590static void AnimateBubbleCatcher(TileIndex tile)
591{
592 uint8_t m = GetAnimationFrame(tile);
593
594 if (++m >= 40) {
595 m = 0;
596 DeleteAnimatedTile(tile);
597 }
598 SetAnimationFrame(tile, m);
599
601}
602
603static void AnimatePowerPlantSparks(TileIndex tile)
604{
605 uint8_t m = GetAnimationFrame(tile);
606 if (m == 6) {
607 SetAnimationFrame(tile, 0);
608 DeleteAnimatedTile(tile);
609 } else {
610 SetAnimationFrame(tile, m + 1);
611 }
613}
614
615static void AnimateToyFactory(TileIndex tile)
616{
617 uint8_t m = GetAnimationFrame(tile) + 1;
618
619 switch (m) {
620 case 1: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2C_TOY_FACTORY_1, tile); break;
621 case 23: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2B_TOY_FACTORY_2, tile); break;
622 case 28: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2A_TOY_FACTORY_3, tile); break;
623 default:
624 if (m >= 50) {
625 int n = GetIndustryAnimationLoop(tile) + 1;
626 m = 0;
627 if (n >= 8) {
628 n = 0;
629 DeleteAnimatedTile(tile);
630 }
632 }
633 }
634
635 SetAnimationFrame(tile, m);
637}
638
639static void AnimatePlasticFountain(TileIndex tile, IndustryGfx gfx)
640{
641 gfx = (gfx < GFX_PLASTIC_FOUNTAIN_ANIMATED_8) ? gfx + 1 : GFX_PLASTIC_FOUNTAIN_ANIMATED_1;
642 SetIndustryGfx(tile, gfx);
644}
645
646static void AnimateOilWell(TileIndex tile, IndustryGfx gfx)
647{
648 bool b = Chance16(1, 7);
649 uint8_t m = GetAnimationFrame(tile) + 1;
650 if (m == 4 && (m = 0, ++gfx) == GFX_OILWELL_ANIMATED_3 + 1 && (gfx = GFX_OILWELL_ANIMATED_1, b)) {
651 SetIndustryGfx(tile, GFX_OILWELL_NOT_ANIMATED);
653 DeleteAnimatedTile(tile);
654 } else {
655 SetAnimationFrame(tile, m);
656 SetIndustryGfx(tile, gfx);
657 }
659}
660
661static void AnimateMineTower(TileIndex tile)
662{
663 int state = TimerGameTick::counter & 0x7FF;
664
665 if ((state -= 0x400) < 0) return;
666
667 if (state < 0x1A0) {
668 if (state < 0x20 || state >= 0x180) {
669 uint8_t m = GetAnimationFrame(tile);
670 if (!(m & 0x40)) {
671 SetAnimationFrame(tile, m | 0x40);
672 if (_settings_client.sound.ambient) SndPlayTileFx(SND_0B_MINE, tile);
673 }
674 if (state & 7) return;
675 } else {
676 if (state & 3) return;
677 }
678 uint8_t m = (GetAnimationFrame(tile) + 1) | 0x40;
679 if (m > 0xC2) m = 0xC0;
680 SetAnimationFrame(tile, m);
682 } else if (state >= 0x200 && state < 0x3A0) {
683 int i = (state < 0x220 || state >= 0x380) ? 7 : 3;
684 if (state & i) return;
685
686 uint8_t m = (GetAnimationFrame(tile) & 0xBF) - 1;
687 if (m < 0x80) m = 0x82;
688 SetAnimationFrame(tile, m);
690 }
691}
692
695{
696 IndustryGfx gfx = GetIndustryGfx(tile);
697
698 if (GetIndustryTileSpec(gfx)->animation.status != AnimationStatus::NoAnimation) {
699 AnimateNewIndustryTile(tile);
700 return;
701 }
702
703 switch (gfx) {
704 case GFX_SUGAR_MINE_SIEVE:
705 if ((TimerGameTick::counter & 1) == 0) AnimateSugarSieve(tile);
706 break;
707
708 case GFX_TOFFEE_QUARRY:
709 if ((TimerGameTick::counter & 3) == 0) AnimateToffeeQuarry(tile);
710 break;
711
712 case GFX_BUBBLE_CATCHER:
713 if ((TimerGameTick::counter & 1) == 0) AnimateBubbleCatcher(tile);
714 break;
715
716 case GFX_POWERPLANT_SPARKS:
717 if ((TimerGameTick::counter & 3) == 0) AnimatePowerPlantSparks(tile);
718 break;
719
720 case GFX_TOY_FACTORY:
721 if ((TimerGameTick::counter & 1) == 0) AnimateToyFactory(tile);
722 break;
723
724 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
725 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
726 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
727 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
728 if ((TimerGameTick::counter & 3) == 0) AnimatePlasticFountain(tile, gfx);
729 break;
730
731 case GFX_OILWELL_ANIMATED_1:
732 case GFX_OILWELL_ANIMATED_2:
733 case GFX_OILWELL_ANIMATED_3:
734 if ((TimerGameTick::counter & 7) == 0) AnimateOilWell(tile, gfx);
735 break;
736
737 case GFX_COAL_MINE_TOWER_ANIMATED:
738 case GFX_COPPER_MINE_TOWER_ANIMATED:
739 case GFX_GOLD_MINE_TOWER_ANIMATED:
740 AnimateMineTower(tile);
741 break;
742 }
743}
744
745static void CreateChimneySmoke(TileIndex tile)
746{
747 uint x = TileX(tile) * TILE_SIZE;
748 uint y = TileY(tile) * TILE_SIZE;
749 int z = GetTileMaxPixelZ(tile);
750
751 CreateEffectVehicle(x + 15, y + 14, z + 59, EV_CHIMNEY_SMOKE);
752}
753
754static void MakeIndustryTileBigger(TileIndex tile)
755{
756 uint8_t cnt = GetIndustryConstructionCounter(tile) + 1;
757 if (cnt != 4) {
759 return;
760 }
761
762 uint8_t stage = GetIndustryConstructionStage(tile) + 1;
764 SetIndustryConstructionStage(tile, stage);
765 TriggerIndustryTileAnimation_ConstructionStageChanged(tile, false);
766 if (stage == INDUSTRY_COMPLETED) SetIndustryCompleted(tile);
767
769
770 if (!IsIndustryCompleted(tile)) return;
771
772 IndustryGfx gfx = GetIndustryGfx(tile);
773 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
774 /* New industries are already animated on construction. */
775 return;
776 }
777
778 switch (gfx) {
779 case GFX_POWERPLANT_CHIMNEY:
780 CreateChimneySmoke(tile);
781 break;
782
783 case GFX_OILRIG_1: {
784 /* Do not require an industry tile to be after the first two GFX_OILRIG_1
785 * tiles (like the default oil rig). Do a proper check to ensure the
786 * tiles belong to the same industry and based on that build the oil rig's
787 * station. */
788 TileIndex other = tile + TileDiffXY(0, 1);
789
790 if (IsTileType(other, TileType::Industry) &&
791 GetIndustryGfx(other) == GFX_OILRIG_1 &&
792 GetIndustryIndex(tile) == GetIndustryIndex(other)) {
793 BuildOilRig(tile);
794 }
795 break;
796 }
797
798 case GFX_TOY_FACTORY:
799 case GFX_BUBBLE_CATCHER:
800 case GFX_TOFFEE_QUARRY:
801 SetAnimationFrame(tile, 0);
803 break;
804
805 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
806 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
807 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
808 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
809 AddAnimatedTile(tile, false);
810 break;
811 }
812}
813
814static void TileLoopIndustry_BubbleGenerator(TileIndex tile)
815{
816 static const int8_t _bubble_spawn_location[3][4] = {
817 { 11, 0, -4, -14 },
818 { -4, -10, -4, 1 },
819 { 49, 59, 60, 65 },
820 };
821
822 if (_settings_client.sound.ambient) SndPlayTileFx(SND_2E_BUBBLE_GENERATOR, tile);
823
824 int dir = Random() & 3;
825
827 TileX(tile) * TILE_SIZE + _bubble_spawn_location[0][dir],
828 TileY(tile) * TILE_SIZE + _bubble_spawn_location[1][dir],
829 _bubble_spawn_location[2][dir],
831 );
832
833 if (v != nullptr) v->animation_substate = dir;
834}
835
838{
839 if (IsTileOnWater(tile)) TileLoop_Water(tile);
840
841 /* Normally this doesn't happen, but if an industry NewGRF is removed
842 * an industry that was previously build on water can now be flooded.
843 * If this happens the tile is no longer an industry tile after
844 * returning from TileLoop_Water. */
845 if (!IsTileType(tile, TileType::Industry)) return;
846
848
849 if (!IsIndustryCompleted(tile)) {
850 MakeIndustryTileBigger(tile);
851 return;
852 }
853
854 if (_game_mode == GameMode::Editor) return;
855
856 if (TransportIndustryGoods(tile) && !TriggerIndustryAnimation(Industry::GetByTile(tile), IndustryAnimationTrigger::CargoDistributed)) {
858
859 if (newgfx != INDUSTRYTILE_NOANIM) {
862 SetIndustryGfx(tile, newgfx);
864 return;
865 }
866 }
867
868 if (TriggerIndustryTileAnimation(tile, IndustryAnimationTrigger::TileLoop)) return;
869
870 IndustryGfx newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_next;
871 if (newgfx != INDUSTRYTILE_NOANIM) {
873 SetIndustryGfx(tile, newgfx);
875 return;
876 }
877
878 IndustryGfx gfx = GetIndustryGfx(tile);
879 switch (gfx) {
880 case GFX_COAL_MINE_TOWER_NOT_ANIMATED:
881 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED:
882 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED:
883 if (!(TimerGameTick::counter & 0x400) && Chance16(1, 2)) {
884 switch (gfx) {
885 case GFX_COAL_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COAL_MINE_TOWER_ANIMATED; break;
886 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_ANIMATED; break;
887 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_ANIMATED; break;
888 }
889 SetIndustryGfx(tile, gfx);
890 SetAnimationFrame(tile, 0x80);
891 AddAnimatedTile(tile);
892 }
893 break;
894
895 case GFX_OILWELL_NOT_ANIMATED:
896 if (Chance16(1, 6)) {
897 SetIndustryGfx(tile, GFX_OILWELL_ANIMATED_1);
898 SetAnimationFrame(tile, 0);
899 AddAnimatedTile(tile);
900 }
901 break;
902
903 case GFX_COAL_MINE_TOWER_ANIMATED:
904 case GFX_COPPER_MINE_TOWER_ANIMATED:
905 case GFX_GOLD_MINE_TOWER_ANIMATED:
906 if (!(TimerGameTick::counter & 0x400)) {
907 switch (gfx) {
908 case GFX_COAL_MINE_TOWER_ANIMATED: gfx = GFX_COAL_MINE_TOWER_NOT_ANIMATED; break;
909 case GFX_COPPER_MINE_TOWER_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_NOT_ANIMATED; break;
910 case GFX_GOLD_MINE_TOWER_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_NOT_ANIMATED; break;
911 }
912 SetIndustryGfx(tile, gfx);
915 DeleteAnimatedTile(tile);
917 }
918 break;
919
920 case GFX_POWERPLANT_SPARKS:
921 if (Chance16(1, 3)) {
922 if (_settings_client.sound.ambient) SndPlayTileFx(SND_0C_POWER_STATION, tile);
923 AddAnimatedTile(tile);
924 }
925 break;
926
927 case GFX_COPPER_MINE_CHIMNEY:
929 break;
930
931
932 case GFX_TOY_FACTORY: {
933 Industry *i = Industry::GetByTile(tile);
934 if (i->was_cargo_delivered) {
935 i->was_cargo_delivered = false;
937 AddAnimatedTile(tile);
938 }
939 }
940 break;
941
942 case GFX_BUBBLE_GENERATOR:
943 TileLoopIndustry_BubbleGenerator(tile);
944 break;
945
946 case GFX_TOFFEE_QUARRY:
947 AddAnimatedTile(tile);
948 break;
949
950 case GFX_SUGAR_MINE_SIEVE:
951 if (Chance16(1, 3)) AddAnimatedTile(tile);
952 break;
953 }
954}
955
958{
959 ShowIndustryViewWindow(GetIndustryIndex(tile));
960 return true;
961}
962
964static void ChangeTileOwner_Industry(TileIndex tile, Owner old_owner, Owner new_owner)
965{
966 /* If the founder merges, the industry was created by the merged company */
967 Industry *i = Industry::GetByTile(tile);
968 if (i->founder == old_owner) i->founder = (new_owner == INVALID_OWNER) ? OWNER_NONE : new_owner;
969
970 if (i->exclusive_supplier == old_owner) i->exclusive_supplier = new_owner;
971 if (i->exclusive_consumer == old_owner) i->exclusive_consumer = new_owner;
972}
973
980{
981 /* Check for industry tile */
982 if (!IsTileType(tile, TileType::Industry)) return false;
983
984 const Industry *ind = Industry::GetByTile(tile);
985
986 /* Check for organic industry (i.e. not processing or extractive) */
988
989 /* Check for wood production */
990 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; });
991}
992
993static const uint8_t _plantfarmfield_type[] = {1, 1, 1, 1, 1, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6};
994
1002static bool IsSuitableForFarmField(TileIndex tile, bool allow_fields, bool allow_rough)
1003{
1004 switch (GetTileType(tile)) {
1005 case TileType::Clear:
1006 if (IsSnowTile(tile)) return false;
1007 switch (GetClearGround(tile)) {
1008 case ClearGround::Desert: return false;
1009 case ClearGround::Rough: return allow_rough;
1010 case ClearGround::Fields: return allow_fields;
1011 default: return true;
1012 }
1013 case TileType::Trees: return GetTreeGround(tile) != TreeGround::Shore && (allow_rough || GetTreeGround(tile) != TreeGround::Rough);
1014 default: return false;
1015 }
1016}
1017
1025static void SetupFarmFieldFence(TileIndex tile, int size, uint8_t type, DiagDirection side)
1026{
1028 TileIndexDiff neighbour_diff = TileOffsByDiagDir(side);
1029
1030 do {
1031 tile = Map::WrapToMap(tile);
1032
1034 TileIndex neighbour = tile + neighbour_diff;
1035 if (!IsTileType(neighbour, TileType::Clear) || !IsClearGround(neighbour, ClearGround::Fields) || GetFence(neighbour, ReverseDiagDir(side)) == 0) {
1036 /* Add fence as long as neighbouring tile does not already have a fence in the same position. */
1037 uint8_t or_ = type;
1038
1039 if (or_ == 1 && Chance16(1, 7)) or_ = 2;
1040
1041 SetFence(tile, side, or_);
1042 }
1043 }
1044
1045 tile += diff;
1046 } while (--size);
1047}
1048
1049static void PlantFarmField(TileIndex tile, IndustryID industry)
1050{
1051 if (_settings_game.game_creation.landscape == LandscapeType::Arctic) {
1052 if (GetTileZ(tile) + 2 >= GetSnowLine()) return;
1053 }
1054
1055 /* determine field size */
1056 uint32_t r = (Random() & 0x303) + 0x404;
1057 if (_settings_game.game_creation.landscape == LandscapeType::Arctic) r += 0x404;
1058 uint size_x = GB(r, 0, 8);
1059 uint size_y = GB(r, 8, 8);
1060
1061 TileArea ta(tile - TileDiffXY(std::min(TileX(tile), size_x / 2), std::min(TileY(tile), size_y / 2)), size_x, size_y);
1062 ta.ClampToMap();
1063
1064 if (ta.w == 0 || ta.h == 0) return;
1065
1066 /* check the amount of bad tiles */
1067 int count = 0;
1068 for (TileIndex cur_tile : ta) {
1069 assert(cur_tile < Map::Size());
1070 count += IsSuitableForFarmField(cur_tile, false, false);
1071 }
1072 if (count * 2 < ta.w * ta.h) return;
1073
1074 /* determine type of field */
1075 r = Random();
1076 uint counter = GB(r, 5, 3);
1077 uint field_type = GB(r, 8, 8) * 9 >> 8;
1078
1079 /* make field */
1080 for (TileIndex cur_tile : ta) {
1081 assert(cur_tile < Map::Size());
1082 if (IsSuitableForFarmField(cur_tile, true, true)) {
1083 MakeField(cur_tile, field_type, industry);
1084 SetClearCounter(cur_tile, counter);
1085 MarkTileDirtyByTile(cur_tile);
1086 }
1087 }
1088
1089 int type = 3;
1090 if (_settings_game.game_creation.landscape != LandscapeType::Arctic && _settings_game.game_creation.landscape != LandscapeType::Tropic) {
1091 type = _plantfarmfield_type[Random() & 0xF];
1092 }
1093
1094 SetupFarmFieldFence(ta.tile, ta.h, type, DiagDirection::NE);
1095 SetupFarmFieldFence(ta.tile, ta.w, type, DiagDirection::NW);
1096 SetupFarmFieldFence(ta.tile + TileDiffXY(ta.w - 1, 0), ta.h, type, DiagDirection::SW);
1097 SetupFarmFieldFence(ta.tile + TileDiffXY(0, ta.h - 1), ta.w, type, DiagDirection::SE);
1098}
1099
1100void PlantRandomFarmField(const Industry *i)
1101{
1102 int x = i->location.w / 2 + Random() % 31 - 16;
1103 int y = i->location.h / 2 + Random() % 31 - 16;
1104
1105 TileIndex tile = TileAddWrap(i->location.tile, x, y);
1106
1107 if (tile != INVALID_TILE) PlantFarmField(tile, i->index);
1108}
1109
1115{
1116 /* Don't process lumber mill if cargo is not set up correctly. */
1117 auto itp = std::begin(i->produced);
1118 if (itp == std::end(i->produced) || !IsValidCargoType(itp->cargo)) return;
1119
1120 /* We only want to cut trees if all tiles are completed. */
1121 for (TileIndex tile_cur : i->location) {
1122 if (i->TileBelongsToIndustry(tile_cur)) {
1123 if (!IsIndustryCompleted(tile_cur)) return;
1124 }
1125 }
1126
1127 for (auto tile : SpiralTileSequence(i->location.tile, 40)) { // 40x40 tiles to search.
1128 if (!IsTileType(tile, TileType::Trees) || GetTreeGrowth(tile) < TreeGrowthStage::Grown) continue;
1129
1130 /* found a tree */
1131 _industry_sound_ctr = 1;
1132 _industry_sound_tile = tile;
1133 if (_settings_client.sound.ambient) SndPlayTileFx(SND_38_LUMBER_MILL_1, tile);
1134
1136 Command<Commands::LandscapeClear>::Do(DoCommandFlag::Execute, tile);
1137
1138 /* Add according value to waiting cargo. */
1139 itp->waiting = ClampTo<uint16_t>(itp->waiting + ScaleByCargoScale(45, false));
1140 break;
1141 }
1142}
1143
1149static void ProduceIndustryGoodsHelper(Industry *i, bool scale)
1150{
1151 for (auto &p : i->produced) {
1152 if (!IsValidCargoType(p.cargo)) continue;
1153
1154 uint16_t amount = p.rate;
1155 if (scale) amount = ScaleByCargoScale(amount, false);
1156
1157 p.waiting = ClampTo<uint16_t>(p.waiting + amount);
1158 }
1159}
1160
1161static void ProduceIndustryGoods(Industry *i)
1162{
1163 const IndustrySpec *indsp = GetIndustrySpec(i->type);
1164
1165 /* play a sound? */
1166 if ((i->counter & 0x3F) == 0) {
1167 uint32_t r;
1168 if (Chance16R(1, 14, r) && !indsp->random_sounds.empty() && _settings_client.sound.ambient) {
1169 if (std::any_of(std::begin(i->produced), std::end(i->produced), [](const auto &p) { return p.history[LAST_MONTH].production > 0; })) {
1170 /* Play sound since last month had production */
1171 SndPlayTileFx(
1172 static_cast<SoundFx>(indsp->random_sounds[((r >> 16) * indsp->random_sounds.size()) >> 16]),
1173 i->location.tile);
1174 }
1175 }
1176 }
1177
1178 i->counter--;
1179
1180 /* If using an industry callback, scale the callback interval by cargo scale percentage. */
1185 }
1186 }
1187
1188 /*
1189 * All other production and special effects happen every 256 ticks, and cargo production is just scaled by the cargo scale percentage.
1190 * 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.
1191 */
1192 if ((i->counter % Ticks::INDUSTRY_PRODUCE_TICKS) == 0) {
1193 /* Handle non-callback cargo production. */
1195
1196 IndustryBehaviours indbehav = indsp->behaviour;
1197
1198 if (indbehav.Test(IndustryBehaviour::PlantFields)) {
1199 uint16_t cb_res = CALLBACK_FAILED;
1201 cb_res = GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 0, i, i->type, i->location.tile);
1202 }
1203
1204 bool plant;
1205 if (cb_res != CALLBACK_FAILED) {
1207 } else {
1208 plant = Chance16(1, 8);
1209 }
1210
1211 if (plant) PlantRandomFarmField(i);
1212 }
1213 if (indbehav.Test(IndustryBehaviour::CutTrees)) {
1214 uint16_t cb_res = CALLBACK_FAILED;
1216 cb_res = GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 1, i, i->type, i->location.tile);
1217 }
1218
1219 bool cut;
1220 if (cb_res != CALLBACK_FAILED) {
1222 } else {
1223 cut = ((i->counter % Ticks::INDUSTRY_CUT_TREE_TICKS) == 0);
1224 }
1225
1226 if (cut) ChopLumberMillTrees(i);
1227 }
1228
1230 TriggerIndustryAnimation(i, IndustryAnimationTrigger::IndustryTick);
1231 }
1232}
1233
1234void OnTick_Industry()
1235{
1236 if (_industry_sound_ctr != 0) {
1237 _industry_sound_ctr++;
1238
1239 if (_industry_sound_ctr == 75) {
1240 if (_settings_client.sound.ambient) SndPlayTileFx(SND_37_LUMBER_MILL_2, _industry_sound_tile);
1241 } else if (_industry_sound_ctr == 160) {
1242 _industry_sound_ctr = 0;
1243 if (_settings_client.sound.ambient) SndPlayTileFx(SND_36_LUMBER_MILL_3, _industry_sound_tile);
1244 }
1245 }
1246
1247 if (_game_mode == GameMode::Editor) return;
1248
1249 for (Industry *i : Industry::Iterate()) {
1250 ProduceIndustryGoods(i);
1251
1252 if ((TimerGameTick::counter + i->index) % Ticks::DAY_TICKS == 0) {
1253 for (auto &a : i->accepted) a.accumulated_waiting += a.waiting;
1254 }
1255 }
1256}
1257
1263{
1264 return CommandCost();
1265}
1266
1273{
1274 if (_settings_game.game_creation.landscape == LandscapeType::Arctic) {
1275 if (GetTileZ(tile) < HighestSnowLine() + 2) {
1276 return CommandCost(STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED);
1277 }
1278 }
1279 return CommandCost();
1280}
1281
1289static bool CheckScaledDistanceFromEdge(TileIndex tile, uint maxdist)
1290{
1291 uint maxdist_x = maxdist;
1292 uint maxdist_y = maxdist;
1293
1294 if (Map::SizeX() > 256) maxdist_x *= Map::SizeX() / 256;
1295 if (Map::SizeY() > 256) maxdist_y *= Map::SizeY() / 256;
1296
1297 if (DistanceFromEdgeDir(tile, DiagDirection::NE) < maxdist_x) return true;
1298 if (DistanceFromEdgeDir(tile, DiagDirection::NW) < maxdist_y) return true;
1299 if (DistanceFromEdgeDir(tile, DiagDirection::SW) < maxdist_x) return true;
1300 if (DistanceFromEdgeDir(tile, DiagDirection::SE) < maxdist_y) return true;
1301
1302 return false;
1303}
1304
1311{
1312 if (_game_mode == GameMode::Editor) return CommandCost();
1313
1314 if (CheckScaledDistanceFromEdge(TileAddXY(tile, 1, 1), _settings_game.game_creation.oil_refinery_limit)) return CommandCost();
1315
1316 return CommandCost(STR_ERROR_CAN_ONLY_BE_POSITIONED);
1317}
1318
1319extern bool _ignore_industry_restrictions;
1320
1327{
1328 if (_game_mode == GameMode::Editor && _ignore_industry_restrictions) return CommandCost();
1329
1330 if (TileHeight(tile) == 0 &&
1331 CheckScaledDistanceFromEdge(TileAddXY(tile, 1, 1), _settings_game.game_creation.oil_refinery_limit)) return CommandCost();
1332
1333 return CommandCost(STR_ERROR_CAN_ONLY_BE_POSITIONED);
1334}
1335
1342{
1343 if (_settings_game.game_creation.landscape == LandscapeType::Arctic) {
1344 if (GetTileZ(tile) + 2 >= HighestSnowLine()) {
1345 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1346 }
1347 }
1348 return CommandCost();
1349}
1350
1357{
1358 if (GetTropicZone(tile) == TropicZone::Desert) {
1359 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1360 }
1361 return CommandCost();
1362}
1363
1370{
1371 if (GetTropicZone(tile) != TropicZone::Desert) {
1372 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT);
1373 }
1374 return CommandCost();
1375}
1376
1383{
1385 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST);
1386 }
1387 return CommandCost();
1388}
1389
1396{
1397 if (GetTileZ(tile) > 4) {
1398 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS);
1399 }
1400 return CommandCost();
1401}
1402
1409
1412 CheckNewIndustry_None, // IndustryCheck::None
1413 CheckNewIndustry_Forest, // IndustryCheck::Forest
1414 CheckNewIndustry_OilRefinery, // IndustryCheck::Refinery
1415 CheckNewIndustry_Farm, // IndustryCheck::Farm
1416 CheckNewIndustry_Plantation, // IndustryCheck::Plantation
1417 CheckNewIndustry_Water, // IndustryCheck::Water
1418 CheckNewIndustry_Lumbermill, // IndustryCheck::Lumbermill
1419 CheckNewIndustry_BubbleGen, // IndustryCheck::BubbleGen
1420 CheckNewIndustry_OilRig, // IndustryCheck::OilRig
1421};
1422
1433static CommandCost FindTownForIndustry(TileIndex tile, IndustryType type, Town **t)
1434{
1435 *t = ClosestTownFromTile(tile, UINT_MAX);
1436
1437 if (_settings_game.economy.multiple_industry_per_town) return CommandCost();
1438
1439 for (const IndustryID &industry : Industry::industries[type]) {
1440 if (Industry::Get(industry)->town == *t) {
1441 *t = nullptr;
1442 return CommandCost(STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN);
1443 }
1444 }
1445
1446 return CommandCost();
1447}
1448
1449bool IsSlopeRefused(Slope current, Slope refused)
1450{
1451 if (IsSteepSlope(current)) return true;
1452 if (current != SLOPE_FLAT) {
1453 if (IsSteepSlope(refused)) return true;
1454
1455 Slope t = ComplementSlope(current);
1456
1457 if ((refused & SLOPE_W) && (t & SLOPE_NW)) return true;
1458 if ((refused & SLOPE_S) && (t & SLOPE_NE)) return true;
1459 if ((refused & SLOPE_E) && (t & SLOPE_SW)) return true;
1460 if ((refused & SLOPE_N) && (t & SLOPE_SE)) return true;
1461 }
1462
1463 return false;
1464}
1465
1473static CommandCost CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTileLayout &layout, IndustryType type)
1474{
1475 IndustryBehaviours ind_behav = GetIndustrySpec(type)->behaviour;
1476
1477 for (const IndustryTileLayoutTile &it : layout) {
1478 IndustryGfx gfx = GetTranslatedIndustryTileID(it.gfx);
1479 TileIndex cur_tile = TileAddWrap(tile, it.ti.x, it.ti.y);
1480
1481 if (!IsValidTile(cur_tile)) {
1482 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1483 }
1484
1485 if (gfx == GFX_WATERTILE_SPECIALCHECK) {
1486 if (!IsWaterTile(cur_tile) ||
1487 !IsTileFlat(cur_tile)) {
1488 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1489 }
1490 } else {
1491 CommandCost ret = EnsureNoVehicleOnGround(cur_tile);
1492 if (ret.Failed()) return ret;
1493 if (IsBridgeAbove(cur_tile)) return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1494
1495 const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
1496
1497 /* Perform land/water check if not disabled */
1498 if (!HasBit(its->slopes_refused, 5) && ((HasTileWaterClass(cur_tile) && IsTileOnWater(cur_tile)) != ind_behav.Test(IndustryBehaviour::BuiltOnWater))) return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1499
1500 if (ind_behav.Any({IndustryBehaviour::OnlyInTown, IndustryBehaviour::Town1200More}) || // Tile must be a house
1501 (ind_behav.Test(IndustryBehaviour::OnlyNearTown) && IsTileType(cur_tile, TileType::House))) { // Tile is allowed to be a house (and it is a house)
1502 if (!IsTileType(cur_tile, TileType::House)) {
1503 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS);
1504 }
1505
1506 /* Clear the tiles as OWNER_TOWN to not affect town rating, and to not clear protected buildings */
1508 ret = Command<Commands::LandscapeClear>::Do({}, cur_tile);
1509
1510 if (ret.Failed()) return ret;
1511 } else {
1512 /* Clear the tiles, but do not affect town ratings */
1513 ret = Command<Commands::LandscapeClear>::Do({DoCommandFlag::Auto, DoCommandFlag::NoTestTownRating, DoCommandFlag::NoModifyTownRating}, cur_tile);
1514 if (ret.Failed()) return ret;
1515 }
1516 }
1517 }
1518
1519 return CommandCost();
1520}
1521
1534static CommandCost CheckIfIndustryTileSlopes(TileIndex tile, const IndustryTileLayout &layout, size_t layout_index, IndustryType type, uint16_t initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type, bool *custom_shape_check = nullptr)
1535{
1536 bool refused_slope = false;
1537 bool custom_shape = false;
1538
1539 for (const IndustryTileLayoutTile &it : layout) {
1540 IndustryGfx gfx = GetTranslatedIndustryTileID(it.gfx);
1541 TileIndex cur_tile = TileAddWrap(tile, it.ti.x, it.ti.y);
1542 assert(IsValidTile(cur_tile)); // checked before in CheckIfIndustryTilesAreFree
1543
1544 if (gfx != GFX_WATERTILE_SPECIALCHECK) {
1545 const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
1546
1548 custom_shape = true;
1549 CommandCost ret = PerformIndustryTileSlopeCheck(tile, cur_tile, its, type, gfx, layout_index, initial_random_bits, founder, creation_type);
1550 if (ret.Failed()) return ret;
1551 } else {
1552 Slope tileh = GetTileSlope(cur_tile);
1553 refused_slope |= IsSlopeRefused(tileh, its->slopes_refused);
1554 }
1555 }
1556 }
1557
1558 if (custom_shape_check != nullptr) *custom_shape_check = custom_shape;
1559
1560 /* It is almost impossible to have a fully flat land in TG, so what we
1561 * do is that we check if we can make the land flat later on. See
1562 * CheckIfCanLevelIndustryPlatform(). */
1563 if (!refused_slope || (_settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world && !custom_shape && !_ignore_industry_restrictions)) {
1564 return CommandCost();
1565 }
1566 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
1567}
1568
1576static CommandCost CheckIfIndustryIsAllowed(TileIndex tile, IndustryType type, const Town *t)
1577{
1578 if (GetIndustrySpec(type)->behaviour.Test(IndustryBehaviour::Town1200More) && t->cache.population < 1200) {
1579 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200);
1580 }
1581
1582 if (GetIndustrySpec(type)->behaviour.Test(IndustryBehaviour::OnlyNearTown) && DistanceMax(t->xy, tile) > 9) {
1583 return CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER);
1584 }
1585
1586 return CommandCost();
1587}
1588
1589static bool CheckCanTerraformSurroundingTiles(TileIndex tile, uint height, int internal)
1590{
1591 /* Check if we don't leave the map */
1592 if (TileX(tile) == 0 || TileY(tile) == 0 || GetTileType(tile) == TileType::Void) return false;
1593
1594 TileArea ta(tile - TileDiffXY(1, 1), 2, 2);
1595 for (TileIndex tile_walk : ta) {
1596 uint curh = TileHeight(tile_walk);
1597 /* Is the tile clear? */
1598 if ((GetTileType(tile_walk) != TileType::Clear) && (GetTileType(tile_walk) != TileType::Trees)) return false;
1599
1600 /* Don't allow too big of a change if this is the sub-tile check */
1601 if (internal != 0 && Delta(curh, height) > 1) return false;
1602
1603 /* Different height, so the surrounding tiles of this tile
1604 * has to be correct too (in level, or almost in level)
1605 * else you get a chain-reaction of terraforming. */
1606 if (internal == 0 && curh != height) {
1607 if (TileX(tile_walk) == 0 || TileY(tile_walk) == 0 || !CheckCanTerraformSurroundingTiles(tile_walk + TileDiffXY(-1, -1), height, internal + 1)) {
1608 return false;
1609 }
1610 }
1611 }
1612
1613 return true;
1614}
1615
1625{
1626 int max_x = 0;
1627 int max_y = 0;
1628
1629 /* Finds dimensions of largest variant of this industry */
1630 for (const IndustryTileLayoutTile &it : layout) {
1631 if (it.gfx == GFX_WATERTILE_SPECIALCHECK) continue; // watercheck tiles don't count for footprint size
1632 if (it.ti.x > max_x) max_x = it.ti.x;
1633 if (it.ti.y > max_y) max_y = it.ti.y;
1634 }
1635
1636 /* Remember level height */
1637 uint h = TileHeight(tile);
1638
1639 if (TileX(tile) <= _settings_game.construction.industry_platform + 1U || TileY(tile) <= _settings_game.construction.industry_platform + 1U) return false;
1640 /* Check that all tiles in area and surrounding are clear
1641 * this determines that there are no obstructing items */
1642
1643 /* TileArea::Expand is not used here as we need to abort
1644 * instead of clamping if the bounds cannot expanded. */
1645 TileArea ta(tile + TileDiffXY(-_settings_game.construction.industry_platform, -_settings_game.construction.industry_platform),
1646 max_x + 2 + 2 * _settings_game.construction.industry_platform, max_y + 2 + 2 * _settings_game.construction.industry_platform);
1647
1648 if (TileX(ta.tile) + ta.w >= Map::MaxX() || TileY(ta.tile) + ta.h >= Map::MaxY()) return false;
1649
1650 /* _current_company is OWNER_NONE for randomly generated industries and in editor, or the company who funded or prospected the industry.
1651 * Perform terraforming as OWNER_TOWN to disable autoslope and town ratings. */
1653
1654 for (TileIndex tile_walk : ta) {
1655 uint curh = TileHeight(tile_walk);
1656 if (curh != h) {
1657 /* This tile needs terraforming. Check if we can do that without
1658 * damaging the surroundings too much. */
1659 if (!CheckCanTerraformSurroundingTiles(tile_walk, h, 0)) {
1660 return false;
1661 }
1662 /* This is not 100% correct check, but the best we can do without modifying the map.
1663 * What is missing, is if the difference in height is more than 1.. */
1664 if (ExtractCommandCost(Command<Commands::TerraformLand>::Do(DoCommandFlags{flags}.Reset(DoCommandFlag::Execute), tile_walk, SLOPE_N, curh <= h)).Failed()) {
1665 return false;
1666 }
1667 }
1668 }
1669
1670 if (flags.Test(DoCommandFlag::Execute)) {
1671 /* Terraform the land under the industry */
1672 for (TileIndex tile_walk : ta) {
1673 uint curh = TileHeight(tile_walk);
1674 while (curh != h) {
1675 /* We give the terraforming for free here, because we can't calculate
1676 * exact cost in the test-round, and as we all know, that will cause
1677 * a nice assert if they don't match ;) */
1678 Command<Commands::TerraformLand>::Do(flags, tile_walk, SLOPE_N, curh <= h);
1679 curh += (curh > h) ? -1 : 1;
1680 }
1681 }
1682 }
1683
1684 return true;
1685}
1686
1687
1695{
1696 const IndustrySpec *indspec = GetIndustrySpec(type);
1697
1698 for (IndustryType conflicting_type : indspec->conflicting) {
1699 if (conflicting_type == IT_INVALID) continue;
1700
1701 for (const IndustryID &industry : Industry::industries[conflicting_type]) {
1702 /* Within 14 tiles from another industry is considered close */
1703 if (DistanceMax(tile, Industry::Get(industry)->location.tile) > 14) continue;
1704
1705 return CommandCost(STR_ERROR_INDUSTRY_TOO_CLOSE);
1706 }
1707 }
1708 return CommandCost();
1709}
1710
1715static void AdvertiseIndustryOpening(const Industry *ind)
1716{
1717 const IndustrySpec *ind_spc = GetIndustrySpec(ind->type);
1718 EncodedString headline;
1719 if (ind_spc->new_industry_text > STR_LAST_STRINGID) {
1720 headline = GetEncodedString(ind_spc->new_industry_text, ind_spc->name, STR_TOWN_NAME, ind->town->index);
1721 } else {
1722 headline = GetEncodedString(ind_spc->new_industry_text, ind_spc->name, ind->town->index);
1723 }
1724 AddIndustryNewsItem(std::move(headline), NewsType::IndustryOpen, ind->index);
1725 AI::BroadcastNewEvent(new ScriptEventIndustryOpen(ind->index));
1726 Game::NewEvent(new ScriptEventIndustryOpen(ind->index));
1727}
1728
1735{
1736 if (ind->neutral_station != nullptr && !_settings_game.station.serve_neutral_industries) {
1737 /* Industry has a neutral station. Use it and ignore any other nearby stations. */
1738 ind->stations_near.insert(ind->neutral_station);
1739 ind->neutral_station->industries_near.clear();
1741 return;
1742 }
1743
1744 ForAllStationsAroundTiles(ind->location, [ind](Station *st, TileIndex tile) {
1745 if (!IsTileType(tile, TileType::Industry) || GetIndustryIndex(tile) != ind->index) return false;
1746 ind->stations_near.insert(st);
1747 st->AddIndustryToDeliver(ind, tile);
1748 return false;
1749 });
1750}
1751
1763static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, const IndustryTileLayout &layout, size_t layout_index, Town *t, Owner founder, uint16_t initial_random_bits)
1764{
1765 const IndustrySpec *indspec = GetIndustrySpec(type);
1766
1767 i->location = TileArea(tile, 1, 1);
1768 i->type = type;
1769
1770 auto &industries = Industry::industries[type];
1771 industries.insert(i->index);
1772
1773 size_t produced_count = 0;
1774 for (size_t index = 0; index < std::size(indspec->produced_cargo); ++index) {
1775 if (IsValidCargoType(indspec->produced_cargo[index])) {
1776 produced_count = index + 1;
1777 }
1778 }
1779 for (size_t index = 0; index < produced_count; ++index) {
1780 Industry::ProducedCargo &p = i->produced.emplace_back();
1781 p.cargo = indspec->produced_cargo[index];
1782 p.rate = indspec->production_rate[index];
1783 }
1784
1785 size_t accepted_count = 0;
1786 for (size_t index = 0; index < std::size(indspec->accepts_cargo); ++index) {
1787 if (IsValidCargoType(indspec->accepts_cargo[index])) {
1788 accepted_count = index + 1;
1789 }
1790 }
1791 for (size_t index = 0; index < accepted_count; ++index) {
1792 Industry::AcceptedCargo &a = i->accepted.emplace_back();
1793 a.cargo = indspec->accepts_cargo[index];
1794 }
1795
1796 /* Randomize initial production if non-original economy is used and there are no production related callbacks. */
1797 if (!indspec->UsesOriginalEconomy()) {
1798 for (auto &p : i->produced) {
1799 p.rate = ClampTo<uint8_t>((RandomRange(256) + 128) * p.rate >> 8);
1800 }
1801 }
1802
1803 i->town = t;
1804 i->owner = OWNER_NONE;
1805
1806 uint16_t r = Random();
1807 i->random_colour = static_cast<Colours>(GB(r, 0, 4));
1808 i->counter = GB(r, 4, 12);
1809 i->random = initial_random_bits;
1810 i->was_cargo_delivered = false;
1812 i->founder = founder;
1813 i->ctlflags = {};
1814
1818
1819 /* Adding 1 here makes it conform to specs of var44 of varaction2 for industries
1820 * 0 = created prior of newindustries
1821 * else, chosen layout + 1 */
1822 i->selected_layout = (uint8_t)(layout_index + 1);
1823
1826
1828
1829 /* Call callbacks after the regular fields got initialised. */
1830
1832 uint16_t res = GetIndustryCallback(CBID_INDUSTRY_PROD_CHANGE_BUILD, 0, Random(), i, type, INVALID_TILE);
1833 if (res != CALLBACK_FAILED) {
1834 if (res < PRODLEVEL_MINIMUM || res > PRODLEVEL_MAXIMUM) {
1836 } else {
1837 i->prod_level = res;
1839 }
1840 }
1841 }
1842
1843 if (_generating_world) {
1846 for (auto &p : i->produced) {
1847 if (IsValidCargoType(p.cargo)) p.history[LAST_MONTH].production = ScaleByCargoScale(p.waiting * 8, false);
1848 p.waiting = 0;
1849 }
1850 }
1851
1852 for (auto &p : i->produced) {
1853 if (IsValidCargoType(p.cargo)) p.history[LAST_MONTH].production += ScaleByCargoScale(p.rate * 8, false);
1854 }
1855
1857 }
1858
1860 uint16_t res = GetIndustryCallback(CBID_INDUSTRY_DECIDE_COLOUR, 0, 0, i, type, INVALID_TILE);
1861 if (res != CALLBACK_FAILED) {
1862 if (GB(res, 4, 11) != 0) ErrorUnknownCallbackResult(indspec->grf_prop.grfid, CBID_INDUSTRY_DECIDE_COLOUR, res);
1863 i->random_colour = static_cast<Colours>(GB(res, 0, 4));
1864 }
1865 }
1866
1868 /* Clear all input cargo types */
1869 i->accepted.clear();
1870 /* Query actual types */
1872 for (uint j = 0; j < maxcargoes; j++) {
1874 if (res == CALLBACK_FAILED || GB(res, 0, 8) == UINT8_MAX) break;
1875 if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
1877 break;
1878 }
1879 CargoType cargo = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
1880 /* Industries without "unlimited" cargo types support depend on the specific order/slots of cargo types.
1881 * They need to be able to blank out specific slots without aborting the callback sequence,
1882 * and solve this by returning undefined cargo indexes. Skip these. */
1884 /* As slots are allocated as needed now, this means we do need to add a slot for the invalid cargo. */
1885 Industry::AcceptedCargo &a = i->accepted.emplace_back();
1886 a.cargo = INVALID_CARGO;
1887 continue;
1888 }
1889 /* Verify valid cargo */
1890 if (std::ranges::find(indspec->accepts_cargo, cargo) == std::end(indspec->accepts_cargo)) {
1891 /* Cargo not in spec, error in NewGRF */
1893 break;
1894 }
1895 if (std::any_of(std::begin(i->accepted), std::begin(i->accepted) + j, [&cargo](const auto &a) { return a.cargo == cargo; })) {
1896 /* Duplicate cargo */
1898 break;
1899 }
1900 Industry::AcceptedCargo &a = i->accepted.emplace_back();
1901 a.cargo = cargo;
1902 }
1903 }
1904
1906 /* Clear all output cargo types */
1907 i->produced.clear();
1908 /* Query actual types */
1910 for (uint j = 0; j < maxcargoes; j++) {
1912 if (res == CALLBACK_FAILED || GB(res, 0, 8) == UINT8_MAX) break;
1913 if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
1915 break;
1916 }
1917 CargoType cargo = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
1918 /* Allow older GRFs to skip slots. */
1920 /* As slots are allocated as needed now, this means we do need to add a slot for the invalid cargo. */
1921 Industry::ProducedCargo &p = i->produced.emplace_back();
1922 p.cargo = INVALID_CARGO;
1923 continue;
1924 }
1925 /* Verify valid cargo */
1926 if (std::ranges::find(indspec->produced_cargo, cargo) == std::end(indspec->produced_cargo)) {
1927 /* Cargo not in spec, error in NewGRF */
1929 break;
1930 }
1931 if (std::any_of(std::begin(i->produced), std::begin(i->produced) + j, [&cargo](const auto &p) { return p.cargo == cargo; })) {
1932 /* Duplicate cargo */
1934 break;
1935 }
1936 Industry::ProducedCargo &p = i->produced.emplace_back();
1937 p.cargo = cargo;
1938 }
1939 }
1940
1941 /* Plant the tiles */
1942
1943 for (const IndustryTileLayoutTile &it : layout) {
1944 TileIndex cur_tile = tile + ToTileIndexDiff(it.ti);
1945
1946 if (it.gfx != GFX_WATERTILE_SPECIALCHECK) {
1947 i->location.Add(cur_tile);
1948
1949 WaterClass wc = (IsWaterTile(cur_tile) ? GetWaterClass(cur_tile) : WaterClass::Invalid);
1950
1951 Command<Commands::LandscapeClear>::Do({DoCommandFlag::Execute, DoCommandFlag::NoTestTownRating, DoCommandFlag::NoModifyTownRating}, cur_tile);
1952
1953 MakeIndustry(cur_tile, i->index, it.gfx, Random(), wc);
1954
1955 if (_generating_world) {
1956 SetIndustryConstructionCounter(cur_tile, 3);
1957 SetIndustryConstructionStage(cur_tile, 2);
1958 }
1959
1960 /* it->gfx is stored in the map. But the translated ID cur_gfx is the interesting one */
1961 IndustryGfx cur_gfx = GetTranslatedIndustryTileID(it.gfx);
1962 const IndustryTileSpec *its = GetIndustryTileSpec(cur_gfx);
1963 if (its->animation.status != AnimationStatus::NoAnimation) AddAnimatedTile(cur_tile);
1964 }
1965 }
1966
1967 /* Call callbacks after all tiles have been created. */
1968 for (TileIndex cur_tile : i->location) {
1969 if (i->TileBelongsToIndustry(cur_tile)) {
1970 /* There are no shared random bits, consistent with "MakeIndustryTileBigger" in tile loop.
1971 * So, trigger tiles individually */
1972 TriggerIndustryTileAnimation_ConstructionStageChanged(cur_tile, true);
1973 }
1974 }
1975
1977 for (uint j = 0; j != 50; j++) PlantRandomFarmField(i);
1978 }
1979 InvalidateWindowData(WindowClass::IndustryDirectory, 0, IDIWD_FORCE_REBUILD);
1980 SetWindowDirty(WindowClass::BuildIndustry, 0);
1981
1983}
1984
2001static 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)
2002{
2003 assert(layout_index < indspec->layouts.size());
2004 const IndustryTileLayout &layout = indspec->layouts[layout_index];
2005
2006 *ip = nullptr;
2007
2008 /* 1. Cheap: Built-in checks on industry level. */
2010 if (ret.Failed()) return ret;
2011
2012 Town *t = nullptr;
2013 ret = FindTownForIndustry(tile, type, &t);
2014 if (ret.Failed()) return ret;
2015 assert(t != nullptr);
2016
2017 ret = CheckIfIndustryIsAllowed(tile, type, t);
2018 if (ret.Failed()) return ret;
2019
2020 /* 2. Built-in checks on industry tiles. */
2021 std::vector<ClearedObjectArea> object_areas(_cleared_object_areas);
2022 ret = CheckIfIndustryTilesAreFree(tile, layout, type);
2023 _cleared_object_areas = std::move(object_areas);
2024 if (ret.Failed()) return ret;
2025
2026 /* 3. NewGRF-defined checks on industry level. */
2027 if (GetIndustrySpec(type)->callback_mask.Test(IndustryCallbackMask::Location)) {
2028 ret = CheckIfCallBackAllowsCreation(tile, type, layout_index, random_var8f, random_initial_bits, founder, creation_type);
2029 } else {
2030 ret = _check_new_industry_procs[indspec->check_proc](tile);
2031 }
2032 if (ret.Failed()) return ret;
2033
2034 /* 4. Expensive: NewGRF-defined checks on industry tiles. */
2035 bool custom_shape_check = false;
2036 ret = CheckIfIndustryTileSlopes(tile, layout, layout_index, type, random_initial_bits, founder, creation_type, &custom_shape_check);
2037 if (ret.Failed()) return ret;
2038
2039 if (!custom_shape_check && _settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world &&
2040 !_ignore_industry_restrictions && !CheckIfCanLevelIndustryPlatform(tile, DoCommandFlag::NoWater, layout)) {
2041 return CommandCost(STR_ERROR_SITE_UNSUITABLE);
2042 }
2043
2044 if (!Industry::CanAllocateItem()) return CommandCost(STR_ERROR_TOO_MANY_INDUSTRIES);
2045
2046 if (flags.Test(DoCommandFlag::Execute)) {
2047 *ip = Industry::Create(tile);
2048 if (!custom_shape_check) CheckIfCanLevelIndustryPlatform(tile, {DoCommandFlag::NoWater, DoCommandFlag::Execute}, layout);
2049 DoCreateNewIndustry(*ip, tile, type, layout, layout_index, t, founder, random_initial_bits);
2050 }
2051
2052 return CommandCost();
2053}
2054
2065CommandCost CmdBuildIndustry(DoCommandFlags flags, TileIndex tile, IndustryType it, uint32_t first_layout, bool fund, uint32_t seed)
2066{
2067 if (it >= NUM_INDUSTRYTYPES) return CMD_ERROR;
2068
2069 const IndustrySpec *indspec = GetIndustrySpec(it);
2070
2071 /* Check if the to-be built/founded industry is available for this climate. */
2072 if (!indspec->enabled || indspec->layouts.empty()) return CMD_ERROR;
2073
2074 /* If the setting for raw-material industries is not on, you cannot build raw-material industries.
2075 * Raw material industries are industries that do not accept cargo (at least for now) */
2076 if (_game_mode != GameMode::Editor && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 0 && indspec->IsRawIndustry()) {
2077 return CMD_ERROR;
2078 }
2079
2081 return CMD_ERROR;
2082 }
2083
2084 Randomizer randomizer;
2085 randomizer.SetSeed(seed);
2086 uint16_t random_initial_bits = GB(seed, 0, 16);
2087 uint32_t random_var8f = randomizer.Next();
2088 size_t num_layouts = indspec->layouts.size();
2089 CommandCost ret = CommandCost(STR_ERROR_SITE_UNSUITABLE);
2090 const bool deity_prospect = _current_company == OWNER_DEITY && !fund;
2091
2092 Industry *ind = nullptr;
2093 if (deity_prospect || (_game_mode != GameMode::Editor && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 2 && indspec->IsRawIndustry())) {
2094 if (flags.Test(DoCommandFlag::Execute)) {
2095 /* Prospecting has a chance to fail, however we cannot guarantee that something can
2096 * be built on the map, so the chance gets lower when the map is fuller, but there
2097 * is nothing we can really do about that. */
2098 bool prospect_success = deity_prospect || Random() <= indspec->prospecting_chance;
2099 if (prospect_success) {
2100 /* Prospected industries are build as OWNER_TOWN to not e.g. be build on owned land of the founder */
2103 for (int i = 0; i < 5000; i++) {
2104 /* We should not have more than one Random() in a function call
2105 * because parameter evaluation order is not guaranteed in the c++ standard
2106 */
2107 tile = RandomTile();
2108 /* Start with a random layout */
2109 size_t layout = RandomRange((uint32_t)num_layouts);
2110 /* Check now each layout, starting with the random one */
2111 for (size_t j = 0; j < num_layouts; j++) {
2112 layout = (layout + 1) % num_layouts;
2113 ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, cur_company.GetOriginalValue(), calltype, &ind);
2114 if (ret.Succeeded()) break;
2115 }
2116 if (ret.Succeeded()) break;
2117 }
2118 }
2119 if (ret.Failed() && IsLocalCompany()) {
2120 if (prospect_success) {
2121 ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_PROSPECT_INDUSTRY), GetEncodedString(STR_ERROR_NO_SUITABLE_PLACES_FOR_PROSPECTING), WarningLevel::Info);
2122 } else {
2123 ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_PROSPECT_INDUSTRY), GetEncodedString(STR_ERROR_PROSPECTING_WAS_UNLUCKY), WarningLevel::Info);
2124 }
2125 }
2126 }
2127 } else {
2128 size_t layout = first_layout;
2129 if (layout >= num_layouts) return CMD_ERROR;
2130
2131 /* Check subsequently each layout, starting with the given layout in p1 */
2132 for (size_t i = 0; i < num_layouts; i++) {
2133 layout = (layout + 1) % num_layouts;
2134 ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, _current_company, _current_company == OWNER_DEITY ? IndustryAvailabilityCallType::RandomCreation : IndustryAvailabilityCallType::UserCreation, &ind);
2135 if (ret.Succeeded()) break;
2136 }
2137
2138 /* If it still failed, there's no suitable layout to build here, return the error */
2139 if (ret.Failed()) return ret;
2140 }
2141
2142 if (flags.Test(DoCommandFlag::Execute) && ind != nullptr && _game_mode != GameMode::Editor) {
2144 }
2145
2147}
2148
2157{
2158 if (_current_company != OWNER_DEITY) return CMD_ERROR;
2159
2160 Industry *ind = Industry::GetIfValid(ind_id);
2161 if (ind == nullptr) return CMD_ERROR;
2162 if (!ctlflags.IsValid()) return CMD_ERROR;
2163
2164 if (flags.Test(DoCommandFlag::Execute)) ind->ctlflags = ctlflags;
2165
2166 return CommandCost();
2167}
2168
2178CommandCost CmdIndustrySetProduction(DoCommandFlags flags, IndustryID ind_id, uint8_t prod_level, bool show_news, const EncodedString &custom_news)
2179{
2180 if (_current_company != OWNER_DEITY) return CMD_ERROR;
2181 if (prod_level < PRODLEVEL_MINIMUM || prod_level > PRODLEVEL_MAXIMUM) return CMD_ERROR;
2182
2183 Industry *ind = Industry::GetIfValid(ind_id);
2184 if (ind == nullptr) return CMD_ERROR;
2185
2186 if (flags.Test(DoCommandFlag::Execute)) {
2188 ind->prod_level = prod_level;
2190
2191 /* Show news message if requested. */
2192 if (show_news && prod_level != ind->prod_level) {
2193 NewsType nt;
2194 switch (WhoCanServiceIndustry(ind)) {
2195 case 0: nt = NewsType::IndustryNobody; break;
2196 case 1: nt = NewsType::IndustryOther; break;
2197 case 2: nt = NewsType::IndustryCompany; break;
2198 default: NOT_REACHED();
2199 }
2200
2201 /* Set parameters of news string */
2202 EncodedString headline;
2203 if (!custom_news.empty()) {
2204 headline = custom_news;
2205 } else {
2206 StringID str = (prod_level > ind->prod_level)
2209
2210 if (str > STR_LAST_STRINGID) {
2211 headline = GetEncodedString(str, STR_TOWN_NAME, ind->town->index, GetIndustrySpec(ind->type)->name);
2212 } else {
2213 headline = GetEncodedString(str, ind->index);
2214 }
2215 }
2216
2217 AddIndustryNewsItem(std::move(headline), nt, ind->index);
2218 }
2219 }
2220
2221 return CommandCost();
2222}
2223
2233CommandCost CmdIndustrySetExclusivity(DoCommandFlags flags, IndustryID ind_id, Owner company_id, bool consumer)
2234{
2235 if (_current_company != OWNER_DEITY) return CMD_ERROR;
2236
2237 Industry *ind = Industry::GetIfValid(ind_id);
2238 if (ind == nullptr) return CMD_ERROR;
2239
2240 if (company_id != OWNER_NONE && company_id != INVALID_OWNER && company_id != OWNER_DEITY
2241 && !Company::IsValidID(company_id)) return CMD_ERROR;
2242
2243 if (flags.Test(DoCommandFlag::Execute)) {
2244 if (consumer) {
2245 ind->exclusive_consumer = company_id;
2246 } else {
2247 ind->exclusive_supplier = company_id;
2248 }
2249 }
2250
2251
2252 return CommandCost();
2253}
2254
2262CommandCost CmdIndustrySetText(DoCommandFlags flags, IndustryID ind_id, const EncodedString &text)
2263{
2264 if (_current_company != OWNER_DEITY) return CMD_ERROR;
2265
2266 Industry *ind = Industry::GetIfValid(ind_id);
2267 if (ind == nullptr) return CMD_ERROR;
2268
2269 if (flags.Test(DoCommandFlag::Execute)) {
2270 ind->text.clear();
2271 if (!text.empty()) ind->text = text;
2272 InvalidateWindowData(WindowClass::IndustryView, ind->index);
2273 }
2274
2275 return CommandCost();
2276}
2277
2285static Industry *CreateNewIndustry(TileIndex tile, IndustryType type, IndustryAvailabilityCallType creation_type)
2286{
2287 const IndustrySpec *indspec = GetIndustrySpec(type);
2288
2289 uint32_t seed = Random();
2290 uint32_t seed2 = Random();
2291 Industry *i = nullptr;
2292 size_t layout_index = RandomRange((uint32_t)indspec->layouts.size());
2293 [[maybe_unused]] CommandCost ret = CreateNewIndustryHelper(tile, type, DoCommandFlag::Execute, indspec, layout_index, seed, GB(seed2, 0, 16), OWNER_NONE, creation_type, &i);
2294 assert(i != nullptr || ret.Failed());
2295 return i;
2296}
2297
2305static uint32_t GetScaledIndustryGenerationProbability(IndustryType it, std::optional<bool> water, bool *force_at_least_one)
2306{
2307 const IndustrySpec *ind_spc = GetIndustrySpec(it);
2308 if (water.has_value() && ind_spc->behaviour.Test(IndustryBehaviour::BuiltOnWater) != *water) return 0;
2309
2310 uint32_t chance = ind_spc->appear_creation[to_underlying(_settings_game.game_creation.landscape)];
2311 if (!ind_spc->enabled || ind_spc->layouts.empty() ||
2312 (_game_mode != GameMode::Editor && _settings_game.difficulty.industry_density == IndustryDensity::FundedOnly) ||
2314 *force_at_least_one = false;
2315 return 0;
2316 } else {
2317 chance *= 16; // to increase precision
2318 /* We want industries appearing at coast to appear less often on bigger maps, as length of coast increases slower than map area.
2319 * For simplicity we scale in both cases, though scaling the probabilities of all industries has no effect. */
2320 chance = (ind_spc->check_proc == IndustryCheck::Refinery || ind_spc->check_proc == IndustryCheck::OilRig) ? Map::ScaleBySize1D(chance) : Map::ScaleBySize(chance);
2321
2322 *force_at_least_one = (chance > 0) && !ind_spc->behaviour.Test(IndustryBehaviour::NoBuildMapCreation) && (_game_mode != GameMode::Editor);
2323 return chance;
2324 }
2325}
2326
2333static uint16_t GetIndustryGamePlayProbability(IndustryType it, uint8_t *min_number)
2334{
2335 if (_settings_game.difficulty.industry_density == IndustryDensity::FundedOnly) {
2336 *min_number = 0;
2337 return 0;
2338 }
2339
2340 const IndustrySpec *ind_spc = GetIndustrySpec(it);
2341 uint8_t chance = ind_spc->appear_ingame[to_underlying(_settings_game.game_creation.landscape)];
2342 if (!ind_spc->enabled || ind_spc->layouts.empty() ||
2346 *min_number = 0;
2347 return 0;
2348 }
2349 *min_number = ind_spc->behaviour.Test(IndustryBehaviour::CanCloseLastInstance) ? 1 : 0;
2350 return chance;
2351}
2352
2358{
2359 /* Number of industries on a 256x256 map. */
2360 static const uint16_t numof_industry_table[] = {
2361 0, // none
2362 0, // minimal
2363 10, // very low
2364 25, // low
2365 55, // normal
2366 80, // high
2367 0, // custom
2368 };
2369
2370 assert(lengthof(numof_industry_table) == to_underlying(IndustryDensity::End));
2371 IndustryDensity density = (_game_mode != GameMode::Editor) ? _settings_game.difficulty.industry_density : IndustryDensity::VeryLow;
2372
2373 if (density == IndustryDensity::Custom) return std::min<uint>(IndustryPool::MAX_SIZE, _settings_game.game_creation.custom_industry_number);
2374
2375 return std::min<uint>(IndustryPool::MAX_SIZE, Map::ScaleBySize(numof_industry_table[to_underlying(density)]));
2376}
2377
2387static Industry *PlaceIndustry(IndustryType type, IndustryAvailabilityCallType creation_type, bool try_hard)
2388{
2389 uint tries = try_hard ? 10000u : 2000u;
2390 for (; tries > 0; tries--) {
2391 Industry *ind = CreateNewIndustry(RandomTile(), type, creation_type);
2392 if (ind != nullptr) return ind;
2393 }
2394 return nullptr;
2395}
2396
2410
2416{
2417 uint total = 0;
2418 for (const auto &industries : Industry::industries) {
2419 total += static_cast<uint16_t>(std::size(industries));
2420 }
2421 return total;
2422}
2423
2424
2427{
2428 this->probability = 0;
2429 this->min_number = 0;
2430 this->target_count = 0;
2431 this->max_wait = 1;
2432 this->wait_count = 0;
2433}
2434
2437{
2439
2440 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2441 this->builddata[it].Reset();
2442 }
2443}
2444
2447{
2448 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.
2449 if (_settings_game.difficulty.industry_density == IndustryDensity::FundedOnly) return; // 'no industries' setting.
2450
2451 /* To prevent running out of unused industries for the player to connect,
2452 * add a fraction of new industries each month, but only if the manager can keep up. */
2453 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).
2454 if (GetCurrentTotalNumberOfIndustries() + max_behind >= (this->wanted_inds >> 16)) {
2455 this->wanted_inds += Map::ScaleBySize(NEWINDS_PER_MONTH);
2456 }
2457}
2458
2460 std::array<uint32_t, NUM_INDUSTRYTYPES> probs{};
2461 std::array<bool, NUM_INDUSTRYTYPES> force_one{};
2462 uint64_t total = 0;
2463 uint num_forced = 0;
2464};
2465
2472{
2474
2475 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2476 p.probs[it] = GetScaledIndustryGenerationProbability(it, water, &p.force_one[it]);
2477 p.total += p.probs[it];
2478 if (p.force_one[it]) p.num_forced++;
2479 }
2480
2481 return p;
2482}
2483
2489{
2490 if (_game_mode != GameMode::Editor && _settings_game.difficulty.industry_density == IndustryDensity::FundedOnly) return; // No industries in the game.
2491
2492 /* Get the probabilities for all industries. This is done first as we need the total of
2493 * both land and water for scaling later. */
2496
2497 /* Run generation twice, for land and water industries in turn. */
2498 for (bool water = false;; water = true) {
2499 auto &p = water ? wprob : lprob;
2500
2501 /* Total number of industries scaled by land/water proportion. */
2502 uint total_amount = 0;
2503 if (lprob.total + wprob.total > 0) total_amount = p.total * GetNumberOfIndustries() / (lprob.total + wprob.total);
2504
2505 /* Scale land-based industries to the land proportion, unless the player has set a custom industry count. */
2506 if (!water && _settings_game.difficulty.industry_density != IndustryDensity::Custom) total_amount = Map::ScaleByLandProportion(total_amount);
2507
2508 /* Ensure that forced industries are generated even if the scaled amounts are too low. */
2509 if (p.total == 0 || total_amount < p.num_forced) {
2510 /* Only place the forced ones */
2511 total_amount = p.num_forced;
2512 }
2513
2515
2516 /* Try to build one industry per type independent of any probabilities */
2517 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2518 if (p.force_one[it]) {
2519 assert(total_amount > 0);
2520 total_amount--;
2521 PlaceInitialIndustry(it, water, true);
2522 }
2523 }
2524
2525 /* Add the remaining industries according to their probabilities */
2526 for (uint i = 0; i < total_amount; i++) {
2527 uint32_t r = RandomRange(p.total);
2528 IndustryType it = 0;
2529 while (r >= p.probs[it]) {
2530 r -= p.probs[it];
2531 it++;
2532 assert(it < NUM_INDUSTRYTYPES);
2533 }
2534 assert(p.probs[it] > 0);
2535 PlaceInitialIndustry(it, water, false);
2536 }
2537
2538 if (water) break;
2539 }
2540
2541 _industry_builder.Reset();
2542}
2543
2544template <>
2545Industry::ProducedHistory SumHistory(std::span<const Industry::ProducedHistory> history)
2546{
2547 uint32_t production = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const auto &p) { return r + p.production; });
2548 uint32_t transported = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const auto &p) { return r + p.transported; });
2549 auto count = std::size(history);
2550 return {.production = ClampTo<uint16_t>(production / count), .transported = ClampTo<uint16_t>(transported / count)};
2551}
2552
2553template <>
2554Industry::AcceptedHistory SumHistory(std::span<const Industry::AcceptedHistory> history)
2555{
2556 uint32_t accepted = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const auto &a) { return r + a.accepted; });
2557 uint32_t waiting = std::accumulate(std::begin(history), std::end(history), 0, [](uint32_t r, const auto &a) { return r + a.waiting; });;
2558 auto count = std::size(history);
2559 return {.accepted = ClampTo<uint16_t>(accepted / count), .waiting = ClampTo<uint16_t>(waiting / count)};
2560}
2561
2567{
2568 auto month = TimerGameEconomy::month;
2569 UpdateValidHistory(i->valid_history, HISTORY_YEAR, month);
2570
2571 for (auto &p : i->produced) {
2572 if (IsValidCargoType(p.cargo)) {
2573 if (p.history[THIS_MONTH].production != 0) i->last_prod_year = TimerGameEconomy::year;
2574
2575 RotateHistory(p.history, i->valid_history, HISTORY_YEAR, month);
2576 }
2577 }
2578
2579 for (auto &a : i->accepted) {
2580 if (!IsValidCargoType(a.cargo)) continue;
2581 if (a.history == nullptr) continue;
2582
2583 (*a.history)[THIS_MONTH].waiting = GetAndResetAccumulatedAverage<uint16_t>(a.accumulated_waiting);
2584 RotateHistory(*a.history, i->valid_history, HISTORY_YEAR, month);
2585 }
2586}
2587
2593{
2594 const IndustrySpec *indspec = GetIndustrySpec(this->type);
2595 assert(indspec->UsesOriginalEconomy());
2596
2597 /* Rates are rounded up, so e.g. oilrig always produces some passengers */
2598 for (auto &p : this->produced) {
2599 p.rate = ClampTo<uint8_t>(CeilDiv(indspec->production_rate[&p - this->produced.data()] * this->prod_level, PRODLEVEL_DEFAULT));
2600 }
2601}
2602
2603void Industry::FillCachedName() const
2604{
2605 auto tmp_params = MakeParameters(this->index);
2606 this->cached_name = GetStringWithArgs(STR_INDUSTRY_NAME, tmp_params);
2607}
2608
2609void ClearAllIndustryCachedNames()
2610{
2611 for (Industry *ind : Industry::Iterate()) {
2612 ind->cached_name.clear();
2613 }
2614}
2615
2622{
2623 uint8_t min_number;
2625 bool changed = min_number != this->min_number || probability != this->probability;
2626 this->min_number = min_number;
2627 this->probability = probability;
2628 return changed;
2629}
2630
2633{
2634 bool changed = false;
2635 uint num_planned = 0; // Number of industries planned in the industry build data.
2636 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2637 changed |= this->builddata[it].GetIndustryTypeData(it);
2638 num_planned += this->builddata[it].target_count;
2639 }
2640 uint total_amount = this->wanted_inds >> 16; // Desired total number of industries.
2641 changed |= num_planned != total_amount;
2642 if (!changed) return; // All industries are still the same, no need to re-randomize.
2643
2644 /* Initialize the target counts. */
2645 uint force_build = 0; // Number of industries that should always be available.
2646 uint32_t total_prob = 0; // Sum of probabilities.
2647 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2648 IndustryTypeBuildData *ibd = this->builddata + it;
2649 force_build += ibd->min_number;
2650 ibd->target_count = ibd->min_number;
2651 total_prob += ibd->probability;
2652 }
2653
2654 if (total_prob == 0) return; // No buildable industries.
2655
2656 /* Subtract forced industries from the number of industries available for construction. */
2657 total_amount = (total_amount <= force_build) ? 0 : total_amount - force_build;
2658
2659 /* Assign number of industries that should be aimed for, by using the probability as a weight. */
2660 while (total_amount > 0) {
2661 uint32_t r = RandomRange(total_prob);
2662 IndustryType it = 0;
2663 while (r >= this->builddata[it].probability) {
2664 r -= this->builddata[it].probability;
2665 it++;
2666 assert(it < NUM_INDUSTRYTYPES);
2667 }
2668 assert(this->builddata[it].probability > 0);
2669 this->builddata[it].target_count++;
2670 total_amount--;
2671 }
2672}
2673
2678{
2679 this->SetupTargetCount();
2680
2681 int missing = 0; // Number of industries that need to be build.
2682 uint count = 0; // Number of industry types eligible for build.
2683 uint32_t total_prob = 0; // Sum of probabilities.
2684 IndustryType forced_build = NUM_INDUSTRYTYPES; // Industry type that should be forcibly build.
2685 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2686 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
2687 missing += difference;
2688 if (this->builddata[it].wait_count > 0) continue; // This type may not be built now.
2689 if (difference > 0) {
2690 if (Industry::GetIndustryTypeCount(it) == 0 && this->builddata[it].min_number > 0) {
2691 /* An industry that should exist at least once, is not available. Force it, trying the most needed one first. */
2692 if (forced_build == NUM_INDUSTRYTYPES ||
2693 difference > this->builddata[forced_build].target_count - Industry::GetIndustryTypeCount(forced_build)) {
2694 forced_build = it;
2695 }
2696 }
2697 total_prob += difference;
2698 count++;
2699 }
2700 }
2701
2702 if (EconomyIsInRecession() || (forced_build == NUM_INDUSTRYTYPES && (missing <= 0 || total_prob == 0))) count = 0; // Skip creation of an industry.
2703
2704 if (count >= 1) {
2705 /* If not forced, pick a weighted random industry to build.
2706 * For the case that count == 1, there is no need to draw a random number. */
2707 IndustryType it;
2708 if (forced_build != NUM_INDUSTRYTYPES) {
2709 it = forced_build;
2710 } else {
2711 /* Non-forced, select an industry type to build (weighted random). */
2712 uint32_t r = 0; // Initialized to silence the compiler.
2713 if (count > 1) r = RandomRange(total_prob);
2714 for (it = 0; it < NUM_INDUSTRYTYPES; it++) {
2715 if (this->builddata[it].wait_count > 0) continue; // Type may not be built now.
2716 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
2717 if (difference <= 0) continue; // Too many of this kind.
2718 if (count == 1) break;
2719 if (r < (uint)difference) break;
2720 r -= difference;
2721 }
2722 assert(it < NUM_INDUSTRYTYPES && this->builddata[it].target_count > Industry::GetIndustryTypeCount(it));
2723 }
2724
2725 /* Try to create the industry. */
2727 if (ind == nullptr) {
2728 this->builddata[it].wait_count = this->builddata[it].max_wait + 1; // Compensate for decrementing below.
2729 this->builddata[it].max_wait = std::min(1000, this->builddata[it].max_wait + 2);
2730 } else {
2732 this->builddata[it].max_wait = std::max(this->builddata[it].max_wait / 2, 1); // Reduce waiting time of the industry type.
2733 }
2734 }
2735
2736 /* Decrement wait counters. */
2737 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2738 if (this->builddata[it].wait_count > 0) this->builddata[it].wait_count--;
2739 }
2740}
2741
2750static bool CheckIndustryCloseDownProtection(IndustryType type)
2751{
2752 const IndustrySpec *indspec = GetIndustrySpec(type);
2753
2754 /* oil wells (or the industries with that flag set) are always allowed to closedown */
2755 if (indspec->behaviour.Test(IndustryBehaviour::DontIncrProd) && _settings_game.game_creation.landscape == LandscapeType::Temperate) return false;
2757}
2758
2768static void CanCargoServiceIndustry(CargoType cargo, Industry *ind, bool *c_accepts, bool *c_produces)
2769{
2770 if (!IsValidCargoType(cargo)) return;
2771
2772 /* Check for acceptance of cargo */
2773 if (ind->IsCargoAccepted(cargo) && !IndustryTemporarilyRefusesCargo(ind, cargo)) *c_accepts = true;
2774
2775 /* Check for produced cargo */
2776 if (ind->IsCargoProduced(cargo)) *c_produces = true;
2777}
2778
2793{
2794 if (ind->stations_near.empty()) return 0; // No stations found at all => nobody services
2795
2796 int result = 0;
2797 for (const Vehicle *v : Vehicle::Iterate()) {
2798 /* Is it worthwhile to try this vehicle? */
2799 if (v->owner != _local_company && result != 0) continue;
2800
2801 /* Check whether it accepts the right kind of cargo */
2802 bool c_accepts = false;
2803 bool c_produces = false;
2804 if (v->type == VehicleType::Train && v->IsFrontEngine()) {
2805 for (const Vehicle *u = v; u != nullptr; u = u->Next()) {
2806 CanCargoServiceIndustry(u->cargo_type, ind, &c_accepts, &c_produces);
2807 }
2808 } else if (v->type == VehicleType::Road || v->type == VehicleType::Ship || v->type == VehicleType::Aircraft) {
2809 CanCargoServiceIndustry(v->cargo_type, ind, &c_accepts, &c_produces);
2810 } else {
2811 continue;
2812 }
2813 if (!c_accepts && !c_produces) continue; // Wrong cargo
2814
2815 /* Check orders of the vehicle.
2816 * We cannot check the first of shared orders only, since the first vehicle in such a chain
2817 * may have a different cargo type.
2818 */
2819 for (const Order &o : v->Orders()) {
2820 if (o.IsType(OT_GOTO_STATION) && o.GetUnloadType() != OrderUnloadType::Transfer) {
2821 /* Vehicle visits a station to load or unload */
2822 Station *st = Station::Get(o.GetDestination().ToStationID());
2823 assert(st != nullptr);
2824
2825 /* Same cargo produced by industry is dropped here => not serviced by vehicle v */
2826 if (o.GetUnloadType() == OrderUnloadType::Unload && !c_accepts) break;
2827
2828 if (ind->stations_near.find(st) != ind->stations_near.end()) {
2829 if (v->owner == _local_company) return 2; // Company services industry
2830 result = 1; // Competitor services industry
2831 }
2832 }
2833 }
2834 }
2835 return result;
2836}
2837
2845static void ReportNewsProductionChangeIndustry(Industry *ind, CargoType cargo, int percent)
2846{
2847 NewsType nt;
2848
2849 switch (WhoCanServiceIndustry(ind)) {
2850 case 0: nt = NewsType::IndustryNobody; break;
2851 case 1: nt = NewsType::IndustryOther; break;
2852 case 2: nt = NewsType::IndustryCompany; break;
2853 default: NOT_REACHED();
2854 }
2855 AddIndustryNewsItem(
2856 GetEncodedString(percent >= 0 ? STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH : STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH,
2857 CargoSpec::Get(cargo)->name, ind->index, abs(percent)
2858 ),
2859 nt,
2860 ind->index
2861 );
2862}
2863
2864static const uint PERCENT_TRANSPORTED_60 = 153;
2865static const uint PERCENT_TRANSPORTED_80 = 204;
2866
2872static void ChangeIndustryProduction(Industry *i, bool monthly)
2873{
2874 StringID str = STR_NULL;
2875 bool closeit = false;
2876 const IndustrySpec *indspec = GetIndustrySpec(i->type);
2877 bool standard = false;
2878 bool suppress_message = false;
2879 bool recalculate_multipliers = false;
2880 /* use original economy for industries using production related callbacks */
2881 bool original_economy = indspec->UsesOriginalEconomy();
2882 uint8_t div = 0;
2883 uint8_t mul = 0;
2884 int8_t increment = 0;
2885
2887 if (callback_enabled) {
2888 std::array<int32_t, 1> regs100;
2889 uint16_t res = GetIndustryCallback(monthly ? CBID_INDUSTRY_MONTHLYPROD_CHANGE : CBID_INDUSTRY_PRODUCTION_CHANGE, 0, Random(), i, i->type, i->location.tile, regs100);
2890 if (res != CALLBACK_FAILED) { // failed callback means "do nothing"
2891 suppress_message = HasBit(res, 7);
2892 /* Get the custom message if any */
2893 if (HasBit(res, 8)) str = MapGRFStringID(indspec->grf_prop.grfid, GRFStringID(GB(regs100[0], 0, 16)));
2894 res = GB(res, 0, 4);
2895 switch (res) {
2896 default: NOT_REACHED();
2897 case 0x0: break; // Do nothing, but show the custom message if any
2898 case 0x1: div = 1; break; // Halve industry production. If production reaches the quarter of the default, the industry is closed instead.
2899 case 0x2: mul = 1; break; // Double industry production if it hasn't reached eight times of the original yet.
2900 case 0x3: closeit = true; break; // The industry announces imminent closure, and is physically removed from the map next month.
2901 case 0x4: standard = true; break; // Do the standard random production change as if this industry was a primary one.
2902 case 0x5: case 0x6: case 0x7: // Divide production by 4, 8, 16
2903 case 0x8: div = res - 0x3; break; // Divide production by 32
2904 case 0x9: case 0xA: case 0xB: // Multiply production by 4, 8, 16
2905 case 0xC: mul = res - 0x7; break; // Multiply production by 32
2906 case 0xD: // decrement production
2907 case 0xE: // increment production
2908 increment = res == 0x0D ? -1 : 1;
2909 break;
2910 case 0xF: // Set production to third byte of register 0x100
2911 i->prod_level = Clamp(GB(regs100[0], 16, 8), PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
2912 recalculate_multipliers = true;
2913 break;
2914 }
2915 }
2916 } else {
2917 if (monthly == original_economy) return;
2918 if (!original_economy && _settings_game.economy.type == EconomyType::Frozen) return;
2919 if (indspec->life_type == INDUSTRYLIFE_BLACK_HOLE) return;
2920 }
2921
2922 if (standard || (!callback_enabled && indspec->life_type.Any({IndustryLifeType::Organic, IndustryLifeType::Extractive}))) {
2923 /* decrease or increase */
2924 bool only_decrease = indspec->behaviour.Test(IndustryBehaviour::DontIncrProd) && _settings_game.game_creation.landscape == LandscapeType::Temperate;
2925
2926 if (original_economy) {
2927 if (only_decrease || Chance16(1, 3)) {
2928 /* If more than 60% transported, 66% chance of increase, else 33% chance of increase */
2929 if (!only_decrease && (i->GetProduced(0).history[LAST_MONTH].PctTransported() > PERCENT_TRANSPORTED_60) != Chance16(1, 3)) {
2930 mul = 1; // Increase production
2931 } else {
2932 div = 1; // Decrease production
2933 }
2934 }
2935 } else if (_settings_game.economy.type == EconomyType::Smooth) {
2937 for (auto &p : i->produced) {
2938 if (!IsValidCargoType(p.cargo)) continue;
2939 uint32_t r = Random();
2940 int old_prod, new_prod, percent;
2941 new_prod = old_prod = p.rate;
2942
2943 /* 1 in 22 chance to change production rate, randomly up/down depending on percent transported last month */
2944 if (Chance16I(1, 22, r >> 16)) {
2945 int prod_change_direction;
2946 if (only_decrease) {
2947 prod_change_direction = -1;
2948 } else if (p.history[LAST_MONTH].PctTransported() <= PERCENT_TRANSPORTED_60) {
2949 prod_change_direction = Chance16I(1, 3, r) ? 1 : -1;
2950 } else if (p.history[LAST_MONTH].PctTransported() <= PERCENT_TRANSPORTED_80) {
2951 prod_change_direction = Chance16I(2, 3, r) ? 1 : -1;
2952 } else {
2953 prod_change_direction = Chance16I(5, 6, r) ? 1 : -1;
2954 }
2955 new_prod += prod_change_direction * (std::max(((RandomRange(50) + 10) * old_prod) >> 8, 1U));
2956 }
2957
2958 /* Prevent production to overflow or Oil Rig passengers to be over-"produced" */
2959 new_prod = Clamp(new_prod, 1, 255);
2960 if (IsValidCargoType(p.cargo) && p.cargo == GetCargoTypeByLabel(CT_PASSENGERS) && !indspec->behaviour.Test(IndustryBehaviour::NoPaxProdClamp)) {
2961 new_prod = Clamp(new_prod, 0, 16);
2962 }
2963
2964 /* If override flags are set, prevent actually changing production if any was decided on */
2965 if (i->ctlflags.Test(IndustryControlFlag::NoProductionDecrease) && new_prod < old_prod) continue;
2966 if (i->ctlflags.Test(IndustryControlFlag::NoProductionIncrease) && new_prod > old_prod) continue;
2967
2968 /* Do not stop closing the industry when it has the lowest possible production rate */
2969 if (new_prod == old_prod && old_prod > 1) {
2970 closeit = false;
2971 continue;
2972 }
2973
2974 percent = (old_prod == 0) ? 100 : (new_prod * 100 / old_prod - 100);
2975 p.rate = new_prod;
2976
2977 /* Close the industry when it has the lowest possible production rate */
2978 if (new_prod > 1) closeit = false;
2979
2980 if (abs(percent) >= 10) {
2981 ReportNewsProductionChangeIndustry(i, p.cargo, percent);
2982 }
2983 }
2984 }
2985 }
2986
2987 /* If override flags are set, prevent actually changing production if any was decided on */
2988 if (i->ctlflags.Test(IndustryControlFlag::NoProductionDecrease) && (div > 0 || increment < 0)) return;
2989 if (i->ctlflags.Test(IndustryControlFlag::NoProductionIncrease) && (mul > 0 || increment > 0)) return;
2991 div = 0;
2992 mul = 0;
2993 increment = 0;
2994 }
2995
2996 if (!callback_enabled && indspec->life_type.Test(IndustryLifeType::Processing)) {
2997 if (TimerGameEconomy::year - i->last_prod_year >= PROCESSING_INDUSTRY_ABANDONMENT_YEARS && Chance16(1, original_economy ? 2 : 180)) {
2998 closeit = true;
2999 }
3000 }
3001
3002 /* Increase if needed */
3003 while (mul-- != 0 && i->prod_level < PRODLEVEL_MAXIMUM) {
3004 i->prod_level = std::min<int>(i->prod_level * 2, PRODLEVEL_MAXIMUM);
3005 recalculate_multipliers = true;
3006 if (str == STR_NULL) str = indspec->production_up_text;
3007 }
3008
3009 /* Decrease if needed */
3010 while (div-- != 0 && !closeit) {
3011 if (i->prod_level == PRODLEVEL_MINIMUM) {
3012 closeit = true;
3013 break;
3014 } else {
3015 i->prod_level = std::max<int>(i->prod_level / 2, PRODLEVEL_MINIMUM);
3016 recalculate_multipliers = true;
3017 if (str == STR_NULL) str = indspec->production_down_text;
3018 }
3019 }
3020
3021 /* Increase or Decreasing the production level if needed */
3022 if (increment != 0) {
3023 if (increment < 0 && i->prod_level == PRODLEVEL_MINIMUM) {
3024 closeit = true;
3025 } else {
3027 recalculate_multipliers = true;
3028 }
3029 }
3030
3031 /* Recalculate production_rate
3032 * For non-smooth economy these should always be synchronized with prod_level */
3033 if (recalculate_multipliers) i->RecomputeProductionMultipliers();
3034
3035 /* Close if needed and allowed */
3038 SetWindowDirty(WindowClass::IndustryView, i->index);
3039 str = indspec->closure_text;
3040 }
3041
3042 if (!suppress_message && str != STR_NULL) {
3043 NewsType nt;
3044 /* Compute news category */
3045 if (closeit) {
3047 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index));
3048 Game::NewEvent(new ScriptEventIndustryClose(i->index));
3049 } else {
3050 switch (WhoCanServiceIndustry(i)) {
3051 case 0: nt = NewsType::IndustryNobody; break;
3052 case 1: nt = NewsType::IndustryOther; break;
3053 case 2: nt = NewsType::IndustryCompany; break;
3054 default: NOT_REACHED();
3055 }
3056 }
3057 /* Set parameters of news string */
3058 EncodedString headline;
3059 if (str > STR_LAST_STRINGID) {
3060 headline = GetEncodedString(str, STR_TOWN_NAME, i->town->index, indspec->name);
3061 } else if (closeit) {
3062 headline = GetEncodedString(str, STR_FORMAT_INDUSTRY_NAME, i->town->index, indspec->name);
3063 } else {
3064 headline = GetEncodedString(str, i->index);
3065 }
3066 /* and report the news to the user */
3067 if (closeit) {
3068 AddTileNewsItem(std::move(headline), nt, i->location.tile + TileDiffXY(1, 1));
3069 } else {
3070 AddIndustryNewsItem(std::move(headline), nt, i->index);
3071 }
3072 }
3073}
3074
3082static const IntervalTimer<TimerGameEconomy> _economy_industries_daily({TimerGameEconomy::Trigger::Day, TimerGameEconomy::Priority::Industry}, [](auto)
3083{
3084 _economy.industry_daily_change_counter += _economy.industry_daily_increment;
3085
3086 /* Bits 16-31 of industry_construction_counter contain the number of industries to change/create today,
3087 * the lower 16 bit are a fractional part that might accumulate over several days until it
3088 * is sufficient for an industry. */
3089 uint16_t change_loop = _economy.industry_daily_change_counter >> 16;
3090
3091 /* Reset the active part of the counter, just keeping the "fractional part" */
3092 _economy.industry_daily_change_counter &= 0xFFFF;
3093
3094 if (change_loop == 0) {
3095 return; // Nothing to do? get out
3096 }
3097
3099
3100 /* perform the required industry changes for the day */
3101
3102 uint perc = 3; // Between 3% and 9% chance of creating a new industry.
3103 if ((_industry_builder.wanted_inds >> 16) > GetCurrentTotalNumberOfIndustries()) {
3104 perc = std::min(9u, perc + (_industry_builder.wanted_inds >> 16) - GetCurrentTotalNumberOfIndustries());
3105 }
3106 for (uint16_t j = 0; j < change_loop; j++) {
3107 if (Chance16(perc, 100)) {
3108 _industry_builder.TryBuildNewIndustry();
3109 } else {
3111 if (i != nullptr) {
3112 ChangeIndustryProduction(i, false);
3113 SetWindowDirty(WindowClass::IndustryView, i->index);
3114 }
3115 }
3116 }
3117
3118 /* production-change */
3119 InvalidateWindowData(WindowClass::IndustryDirectory, 0, IDIWD_PRODUCTION_CHANGE);
3120});
3121
3123static const IntervalTimer<TimerGameEconomy> _economy_industries_monthly({TimerGameEconomy::Trigger::Month, TimerGameEconomy::Priority::Industry}, [](auto)
3124{
3126
3127 _industry_builder.EconomyMonthlyLoop();
3128
3129 for (Industry *i : Industry::Iterate()) {
3131 if (i->prod_level == PRODLEVEL_CLOSURE) {
3132 delete i;
3133 } else {
3134 ChangeIndustryProduction(i, true);
3135 SetWindowDirty(WindowClass::IndustryView, i->index);
3136 }
3137 }
3138
3139 /* production-change */
3140 InvalidateWindowData(WindowClass::IndustryDirectory, 0, IDIWD_PRODUCTION_CHANGE);
3141});
3142
3143
3144void InitializeIndustries()
3145{
3146 Industry::industries.fill({});
3147 _industry_sound_tile = TileIndex{};
3148
3149 _industry_builder.Reset();
3150}
3151
3154{
3155 int count = 0;
3156 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
3157 if (Industry::GetIndustryTypeCount(it) > 0) continue; // Types of existing industries can be skipped.
3158
3159 bool force_at_least_one;
3160 uint32_t chance = GetScaledIndustryGenerationProbability(it, std::nullopt, &force_at_least_one);
3161 if (chance == 0 || !force_at_least_one) continue; // Types that are not available can be skipped.
3162
3163 const IndustrySpec *is = GetIndustrySpec(it);
3164 ShowErrorMessage(GetEncodedString(STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES, is->name),
3165 GetEncodedString(STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION), WarningLevel::Warning);
3166
3167 count++;
3168 if (count >= 3) break; // Don't swamp the user with errors.
3169 }
3170}
3171
3180
3186{
3187 /* Lumber mills are neither raw nor processing */
3188 return this->life_type.Test(IndustryLifeType::Processing) &&
3190}
3191
3197{
3198 /* Building raw industries like secondary uses different price base */
3199 return (_price[(_settings_game.construction.raw_industry_construction == 1 && this->IsRawIndustry()) ?
3200 Price::BuildIndustryRaw : Price::BuildIndustry] * this->cost_multiplier) >> 8;
3201}
3202
3210{
3212}
3213
3228
3230static CommandCost TerraformTile_Industry(TileIndex tile, DoCommandFlags flags, int z_new, Slope tileh_new)
3231{
3232 if (AutoslopeEnabled()) {
3233 /* We imitate here TTDP's behaviour:
3234 * - Both new and old slope must not be steep.
3235 * - TileMaxZ must not be changed.
3236 * - Allow autoslope by default.
3237 * - Disallow autoslope if callback succeeds and returns non-zero.
3238 */
3239 Slope tileh_old = GetTileSlope(tile);
3240 /* TileMaxZ must not be changed. Slopes must not be steep. */
3241 if (!IsSteepSlope(tileh_old) && !IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) {
3242 const IndustryGfx gfx = GetIndustryGfx(tile);
3243 const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
3244
3245 /* Call callback 3C 'disable autosloping for industry tiles'. */
3247 /* If the callback fails, allow autoslope. */
3248 uint16_t res = GetIndustryTileCallback(CBID_INDTILE_AUTOSLOPE, 0, 0, gfx, Industry::GetByTile(tile), tile);
3250 } else {
3251 /* allow autoslope */
3253 }
3254 }
3255 }
3256 return Command<Commands::LandscapeClear>::Do(flags, tile);
3257}
3258
3261 .draw_tile_proc = DrawTile_Industry,
3262 .get_slope_pixel_z_proc = [](TileIndex tile, uint, uint, bool) { return GetTileMaxPixelZ(tile); },
3263 .clear_tile_proc = ClearTile_Industry,
3264 .add_accepted_cargo_proc = AddAcceptedCargo_Industry,
3265 .get_tile_desc_proc = GetTileDesc_Industry,
3266 .click_tile_proc = ClickTile_Industry,
3267 .animate_tile_proc = AnimateTile_Industry,
3268 .tile_loop_proc = TileLoop_Industry,
3269 .change_tile_owner_proc = ChangeTileOwner_Industry,
3270 .get_foundation_proc = GetFoundation_Industry,
3271 .terraform_tile_proc = TerraformTile_Industry,
3272};
3273
3274bool IndustryCompare::operator() (const IndustryListEntry &lhs, const IndustryListEntry &rhs) const
3275{
3276 /* Compare by distance first and use index as a tiebreaker. */
3277 return std::tie(lhs.distance, lhs.industry->index) < std::tie(rhs.distance, rhs.industry->index);
3278}
3279
3285{
3286 auto ita = std::find_if(std::rbegin(ind->accepted), std::rend(ind->accepted), [](const auto &a) { return IsValidCargoType(a.cargo); });
3287 ind->accepted.erase(ita.base(), std::end(ind->accepted));
3288 ind->accepted.shrink_to_fit();
3289
3290 auto itp = std::find_if(std::rbegin(ind->produced), std::rend(ind->produced), [](const auto &p) { return IsValidCargoType(p.cargo); });
3291 ind->produced.erase(itp.base(), std::end(ind->produced));
3292 ind->produced.shrink_to_fit();
3293}
Base functions for all AIs.
void AddAnimatedTile(TileIndex tile, bool mark_dirty)
Add the given tile to the animated tile table (if it does not exist yet).
void DeleteAnimatedTile(TileIndex tile, bool immediate)
Stops animation on the given tile.
Tile animation!
Functions related to autoslope.
bool AutoslopeEnabled()
Tests if autoslope is enabled for _current_company.
Definition autoslope.h:65
Class for backupping variables and making sure they are restored later.
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
bool IsBridgeAbove(Tile t)
checks if a bridge is set above the ground of this tile
Definition bridge_map.h:45
Tables with default industry layouts and behaviours.
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:110
EnumBitSet< CargoType, uint64_t > CargoTypes
Bitset of CargoType elements.
Definition cargo_type.h:113
static constexpr CargoLabel CT_PASSENGERS
Available types of cargo Labels may be re-used between different climates.
Definition cargo_type.h:31
CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:22
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:250
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr bool IsValid() const
Test that the raw value of this bit set is valid.
constexpr Timpl & Set()
Set all bits.
constexpr bool Any(const Timpl &other) const
Test if any of the given values are set.
Common return value for all commands.
bool Succeeded() const
Did this command succeed?
bool Failed() const
Did this command fail?
Container for an encoded string, created by GetEncodedString.
static void NewEvent(class ScriptEvent *event)
Queue a new event for the game script.
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
Generate TileIndices around a center tile or tile area, with increasing distance.
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
static constexpr TimerGameTick::Ticks INDUSTRY_CUT_TREE_TICKS
Cycle duration for lumber mill's extra action.
static constexpr TimerGameTick::Ticks INDUSTRY_PRODUCE_TICKS
Cycle duration for industry production.
Wrapper class to abstract away the way the tiles are stored.
Definition map_func.h:25
static Date date
Current date in days (day counter).
static Year year
Current year, starting at 0.
static Year year
Current year, starting at 0.
static Month month
Current month (0..11).
static TickCounter counter
Monotonic counter, in ticks, since start of game.
Map accessors for 'clear' tiles.
bool IsClearGround(Tile t, ClearGround ct)
Set the type of clear tile.
Definition clear_map.h:65
void SetFence(Tile t, DiagDirection side, uint h)
Sets the type of fence (and whether there is one) for the given border.
Definition clear_map.h:234
IndustryID GetIndustryIndexOfField(Tile t)
Get the industry (farm) that made the field.
Definition clear_map.h:189
@ Desert
Desert with transition (1,3).
Definition clear_map.h:26
@ Fields
Farm fields (3).
Definition clear_map.h:25
@ Rough
Rough mounds (3).
Definition clear_map.h:23
ClearGround GetClearGround(Tile t)
Get the type of clear tile.
Definition clear_map.h:52
void SetIndustryIndexOfField(Tile t, IndustryID i)
Set the industry (farm) that made the field.
Definition clear_map.h:201
void MakeField(Tile t, uint field_type, IndustryID industry)
Make a (farm) field tile.
Definition clear_map.h:274
void SetClearCounter(Tile t, uint c)
Sets the counter used to advance to the next clear density/field type.
Definition clear_map.h:138
uint GetFence(Tile t, DiagDirection side)
Is there a fence at the given border?
Definition clear_map.h:215
bool IsSnowTile(Tile t)
Test if a tile is covered with snow.
Definition clear_map.h:40
CommandCost CommandCostWithParam(StringID str, uint64_t value)
Return an error status, with string and parameter.
Definition command.cpp:416
Functions related to commands.
CommandCost & ExtractCommandCost(Tret &ret)
Extract the CommandCost from a command proc result.
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
EnumBitSet< DoCommandFlag, uint16_t > DoCommandFlags
Bitset of DoCommandFlag elements.
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.
@ SW
Southwest.
@ NW
Northwest.
@ NE
Northeast, upper right on your monitor.
@ SE
Southeast.
Prices _price
Prices and also the fractional part.
Definition economy.cpp:107
static uint ScaleByInverseCargoScale(uint num, bool town)
Scale a number by the inverse of the cargo scale setting, e.g.
bool EconomyIsInRecession()
Is the economy in recession?
uint ScaleByCargoScale(uint num, bool town)
Scale a number by the cargo scale setting.
@ Original
Imitates original TTD economy.
@ Frozen
Stops production changes and industry closures.
@ Smooth
Makes production changes more often, and in smaller steps.
@ Construction
Construction costs.
@ Other
Other expenses.
@ BuildIndustryRaw
Price for funding new raw industries, e.g. coal mine, forest.
@ BuildFoundation
Price for building foundation under other constructions e.g. roads, rails, depots,...
@ BuildIndustry
Price for funding new industries.
@ ClearIndustry
Price for destroying industries.
EffectVehicle * CreateEffectVehicle(int x, int y, int z, EffectVehicleType type)
Create an effect vehicle at a particular location.
EffectVehicle * CreateEffectVehicleAbove(int x, int y, int z, EffectVehicleType type)
Create an effect vehicle above a particular location.
Base class for all effect vehicles.
Functions related to effect vehicles.
@ EV_BUBBLE
Bubble of bubble generator (industry).
@ EV_CHIMNEY_SMOKE
Smoke of power plant (industry).
@ EV_COPPER_MINE_SMOKE
Smoke at copper mine.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
Definition enum_type.hpp:21
EnumClassIndexContainer< std::array< T, to_underlying(N)>, Index > EnumIndexArray
A typedef for EnumClassIndexContainer using std::array as the backing container type.
Functions related to errors.
@ Warning
Other information.
Definition error.h:25
@ 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
@ WaterIndustries
Generate industries.
Definition genworld.h:66
@ LandIndustries
Generate industries.
Definition genworld.h:65
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
Colours
One of 16 base colours used for companies and windows/widgets.
Definition gfx_type.h:283
uint8_t GetSnowLine()
Get the current snow line, either variable or static.
uint8_t HighestSnowLine()
Get the highest possible snow line height, either variable or static.
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
Mark a tile given by its index dirty for repaint.
void UpdateValidHistory(ValidHistoryMask &valid_history, const HistoryRange &hr, uint cur_month)
Update mask of valid records for a historical data.
Definition history.cpp:25
Functions for storing historical data.
T GetAndResetAccumulatedAverage(Taccrued &total)
Get an average value for the previous month, as reset for the next month.
void RotateHistory(HistoryData< T > &history, ValidHistoryMask valid_history, const HistoryRange &hr, uint cur_month)
Rotate historical data.
Types for storing historical data.
Base of all industries.
static constexpr uint8_t PRODLEVEL_MAXIMUM
the industry is running at full speed
Definition industry.h:38
void ReleaseDisastersTargetingIndustry(IndustryID)
Marks all disasters targeting this industry in such a way they won't call Industry::Get(v->dest_tile)...
static constexpr uint8_t PRODLEVEL_DEFAULT
default level set when the industry is created
Definition industry.h:37
static const TimerGameEconomy::Year PROCESSING_INDUSTRY_ABANDONMENT_YEARS
If a processing industry doesn't produce for this many consecutive economy years, it may close.
Definition industry.h:28
IndustryBuildData _industry_builder
In-game manager of industries.
EnumBitSet< IndustryControlFlag, uint8_t, IndustryControlFlag::End > IndustryControlFlags
Bitset of IndustryControlFlag elements.
Definition industry.h:59
static constexpr uint8_t PRODLEVEL_MINIMUM
below this level, the industry is set to be closing
Definition industry.h:36
static constexpr uint8_t PRODLEVEL_CLOSURE
signal set to actually close the industry
Definition industry.h:35
@ ExternalProdLevel
Indicates that the production level of the industry is externally controlled.
Definition industry.h:54
@ NoClosure
Industry can not close regardless of production level or time since last delivery.
Definition industry.h:52
@ NoProductionDecrease
When industry production change is evaluated, rolls to decrease are ignored.
Definition industry.h:46
@ NoProductionIncrease
When industry production change is evaluated, rolls to increase are ignored.
Definition industry.h:48
static bool ClickTile_Industry(TileIndex tile)
Tile callback function signature for clicking a tile.
const TileTypeProcs _tile_type_industry_procs
TileTypeProcs definitions for TileType::Industry tiles.
Definition landscape.cpp:60
static uint16_t GetIndustryGamePlayProbability(IndustryType it, uint8_t *min_number)
Compute the probability for constructing a new industry during game play.
static void TileLoop_Industry(TileIndex tile)
Tile callback function signature for running periodic tile updates.
static CommandCost CheckNewIndustry_Water(TileIndex tile)
Check the conditions of IndustryCheck::Water (Industry should be in the desert).
static CommandCost CheckNewIndustry_None(TileIndex)
Check the conditions of IndustryCheck::None (Always succeeds).
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 IndustryCheck::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 IndustryCheck::BubbleGen (Industry should be in low land).
static CommandCost CheckNewIndustry_Farm(TileIndex tile)
Check the conditions of IndustryCheck::Farm (Industry should be below snow-line in arctic).
static void AdvertiseIndustryOpening(const Industry *ind)
Advertise about a new industry opening.
static void ChopLumberMillTrees(Industry *i)
Perform a circular search around the Lumber Mill in order to find trees to cut.
static uint32_t GetScaledIndustryGenerationProbability(IndustryType it, std::optional< bool > water, bool *force_at_least_one)
Compute the appearance probability for an industry during map creation.
static bool CheckScaledDistanceFromEdge(TileIndex tile, uint maxdist)
Check if a tile is within a distance from map edges, scaled by map dimensions independently.
static void ReportNewsProductionChangeIndustry(Industry *ind, CargoType cargo, int percent)
Report news that industry production has changed significantly.
static void GetTileDesc_Industry(TileIndex tile, TileDesc &td)
Tile callback function signature for obtaining a tile description.
bool IsTileForestIndustry(TileIndex tile)
Check whether the tile is a forest.
const IndustryTileSpec * GetIndustryTileSpec(IndustryGfx gfx)
Accessor for array _industry_tile_specs.
static void CanCargoServiceIndustry(CargoType cargo, Industry *ind, bool *c_accepts, bool *c_produces)
Can given cargo type be accepted or produced by the industry?
static Foundation GetFoundation_Industry(TileIndex tile, Slope tileh)
Tile callback function signature for getting the foundation of a tile.
void GenerateIndustries()
This function will create random industries during game creation.
static void ProduceIndustryGoodsHelper(Industry *i, bool scale)
Helper for ProduceIndustryGoods that scales and produces cargos.
static void ChangeTileOwner_Industry(TileIndex tile, Owner old_owner, Owner new_owner)
Tile callback function signature for changing the owner of a tile.
static Industry * PlaceIndustry(IndustryType type, IndustryAvailabilityCallType creation_type, bool try_hard)
Try to place the industry in the game.
static bool IsSuitableForFarmField(TileIndex tile, bool allow_fields, bool allow_rough)
Check whether the tile can be replaced by a farm field.
static CommandCost CheckNewIndustry_Plantation(TileIndex tile)
Check the conditions of IndustryCheck::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 IndustryCheck::Forest (Industry should be build above snow-line in arctic cli...
static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, const IndustryTileLayout &layout, size_t layout_index, Town *t, Owner founder, uint16_t initial_random_bits)
Put an industry on the map.
CommandCost CheckNewIndustryProc(TileIndex tile)
Industrytype check function signature.
static CommandCost CreateNewIndustryHelper(TileIndex tile, IndustryType type, DoCommandFlags flags, const IndustrySpec *indspec, size_t layout_index, uint32_t random_var8f, uint16_t random_initial_bits, Owner founder, IndustryAvailabilityCallType creation_type, Industry **ip)
Helper function for Build/Fund an industry.
static int WhoCanServiceIndustry(Industry *ind)
Compute who can service the industry.
void ResetIndustries()
This function initialize the spec arrays of both industry and industry tiles.
static CommandCost CheckIfFarEnoughFromConflictingIndustry(TileIndex tile, IndustryType type)
Check that the new industry is far enough from conflicting industries.
static CommandCost CheckNewIndustry_OilRig(TileIndex tile)
Check the conditions of IndustryCheck::OilRig (Industries at sea should be positioned near edge of th...
void TrimIndustryAcceptedProduced(Industry *ind)
Remove unused industry accepted/produced slots – entries after the last slot with valid cargo.
static uint GetNumberOfIndustries()
Get wanted number of industries on the map.
static void AddAcceptedCargo_Industry(TileIndex tile, CargoArray &acceptance, CargoTypes &always_accepted)
Tile callback function signature for obtaining cargo acceptance of a tile.
CommandCost CmdBuildIndustry(DoCommandFlags flags, TileIndex tile, IndustryType it, uint32_t first_layout, bool fund, uint32_t seed)
Build/Fund an industry.
static CommandCost ClearTile_Industry(TileIndex tile, DoCommandFlags flags)
Tile callback function signature for clearing a tile.
static void PlaceInitialIndustry(IndustryType type, bool water, bool try_hard)
Try to build a industry on the map.
static bool CheckIndustryCloseDownProtection(IndustryType type)
Protects an industry from closure if the appropriate flags and conditions are met CanCloseLastInstanc...
static CommandCost TerraformTile_Industry(TileIndex tile, DoCommandFlags flags, int z_new, Slope tileh_new)
Tile callback function signature of the terraforming callback.
static void AnimateTile_Industry(TileIndex tile)
Tile callback function signature for animating a tile.
static void DrawTile_Industry(TileInfo *ti)
Tile callback function signature for drawing a tile and its contents to the screen.
static void SetupFarmFieldFence(TileIndex tile, int size, uint8_t type, DiagDirection side)
Build farm field fence.
static constexpr EnumIndexArray< CheckNewIndustryProc *const, IndustryCheck, IndustryCheck::End > _check_new_industry_procs
Check functions for different types of industry.
static const IntervalTimer< TimerGameEconomy > _economy_industries_daily({TimerGameEconomy::Trigger::Day, TimerGameEconomy::Priority::Industry}, [](auto) { _economy.industry_daily_change_counter+=_economy.industry_daily_increment;uint16_t change_loop=_economy.industry_daily_change_counter > > 16;_economy.industry_daily_change_counter &=0xFFFF;if(change_loop==0) { return;} AutoRestoreBackup 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(WindowClass::IndustryView, i->index);} } } InvalidateWindowData(WindowClass::IndustryDirectory, 0, IDIWD_PRODUCTION_CHANGE);})
Every economy day handler for the industry changes Taking the original map size of 256*256,...
CommandCost CmdIndustrySetFlags(DoCommandFlags flags, IndustryID ind_id, IndustryControlFlags ctlflags)
Set industry control flags.
IndustryType GetIndustryType(Tile tile)
Retrieve the type for this industry.
static const IntervalTimer< TimerGameEconomy > _economy_industries_monthly({TimerGameEconomy::Trigger::Month, TimerGameEconomy::Priority::Industry}, [](auto) { AutoRestoreBackup cur_company(_current_company, OWNER_NONE);_industry_builder.EconomyMonthlyLoop();for(Industry *i :Industry::Iterate()) { UpdateIndustryStatistics(i);if(i->prod_level==PRODLEVEL_CLOSURE) { delete i;} else { ChangeIndustryProduction(i, true);SetWindowDirty(WindowClass::IndustryView, i->index);} } InvalidateWindowData(WindowClass::IndustryDirectory, 0, IDIWD_PRODUCTION_CHANGE);})
Economy monthly loop for industries.
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 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 IndustryCheck::Lumbermill (Industry should be in the rainforest).
CommandCost CmdIndustrySetText(DoCommandFlags flags, IndustryID ind_id, const EncodedString &text)
Change additional industry text.
Command definitions related to industries.
Information about the behaviour of the default industry tiles.
static const uint8_t _industry_anim_offs_toffee[]
This is ONLY used for Toffee Quarry.
static const Coord2D< uint8_t > _drawtile_proc1[5]
This is ONLY used for Sugar Mine.
static const DrawIndustryAnimationStruct _draw_industry_spec1[96]
This is ONLY used for Sugar Mine.
static const Coord2D< uint8_t > _coal_plant_sparks[]
Movement of the sparks , only used for Power Station.
static const uint8_t _industry_anim_offs_bubbles[]
This is ONLY used for the Bubble Generator.
static const DrawBuildingsTileStruct _industry_draw_tile_data[NEW_INDUSTRYTILEOFFSET *4]
Structure for industry tiles drawing.
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.
EnumBitSet< IndustryBehaviour, uint32_t > IndustryBehaviours
Bitset of IndustryBehaviour elements.
@ Gameplay
either by user or random creation process
@ ScenarioEditor
while editing a scenario
@ MapGeneration
during random map creation
@ OilRig
Industries at sea should be positioned near edge of the map.
@ Refinery
Industry should be positioned near edge of the map.
static constexpr IndustryLifeTypes INDUSTRYLIFE_BLACK_HOLE
Like power plants and banks.
void DrawFoundation(TileInfo *ti, Foundation f)
Draw foundation f at tile ti.
Functions related to OTTD's landscape.
Command definitions related to landscape (slopes etc.).
@ Arctic
Landscape with snow levels.
@ Tropic
Landscape with distinct rainforests and deserts,.
@ Temperate
Base landscape.
uint DistanceMax(TileIndex t0, TileIndex t1)
Gets the biggest distance component (x or y) between the two given tiles.
Definition map.cpp:201
uint DistanceFromEdgeDir(TileIndex tile, DiagDirection dir)
Gets the distance to the edge of the map in given direction.
Definition map.cpp:246
TileIndex TileAddWrap(TileIndex tile, int addx, int addy)
This function checks if we add addx/addy to tile, if we do wrap around the edges.
Definition map.cpp:120
Functions related to maps.
TileIndex TileAddXY(TileIndex tile, int x, int y)
Adds a given offset to a tile.
Definition map_func.h:474
TileIndexDiff ToTileIndexDiff(TileIndexDiffC tidc)
Return the offset between two tiles from a TileIndexDiffC struct.
Definition map_func.h:444
TileIndexDiff TileDiffXY(int x, int y)
Calculates an offset for the given coordinate(-offset).
Definition map_func.h:392
TileIndexDiff TileOffsByAxis(Axis axis)
Convert an Axis to a TileIndexDiff.
Definition map_func.h:559
static uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:429
static uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:419
#define RandomTile()
Get a valid random tile.
Definition map_func.h:656
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition map_func.h:574
int32_t TileIndexDiff
An offset value between two tiles.
Definition map_type.h:23
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition math_func.hpp:23
constexpr uint CeilDiv(uint a, uint b)
Computes ceil(a / b) for non-negative a and b.
constexpr T Delta(const T a, const T b)
Returns the (absolute) difference between two (scalar) variables.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
constexpr uint ClampU(const uint a, const uint min, const uint max)
Clamp an unsigned integer between an interval.
constexpr To ClampTo(From value)
Clamp the given value down to lie within the requested type.
StringID MapGRFStringID(GrfID grfid, GRFStringID str)
Used when setting an object's property to map to the GRF's strings while taking in consideration the ...
@ IndustryTiles
Industry tiles feature.
Definition newgrf.h:88
@ Industries
Industries feature.
Definition newgrf.h:89
const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET]
Extern declaration for _origin_industry_specs in table/build_industry.h.
@ NoAnimation
There is no animation.
@ InputCargoTypes
customize the cargoes the industry requires
@ ProductionChange
controls random production change
@ DecideColour
give a custom colour to newly build industries
@ SpecialEffect
control special effects
@ ProdChangeBuild
initialise production level on construction
@ Production256Ticks
call production callback every 256 ticks
@ Location
check industry construction on given area
@ MonthlyProdChange
controls monthly random production change
@ ProductionCargoArrival
call production callback when cargo arrives at the industry
@ OutputCargoTypes
customize the cargoes the industry produces
@ CBID_INDUSTRY_OUTPUT_CARGO_TYPES
Customize the output cargo types of a newly build industry.
@ CBID_INDUSTRY_SPECIAL_EFFECT
Called to determine industry special effects.
@ CBID_INDTILE_AUTOSLOPE
Called to determine if industry can alter the ground below industry tile.
@ CBID_INDUSTRY_DECIDE_COLOUR
Called to determine the colour of an industry.
@ CBID_INDTILE_DRAW_FOUNDATIONS
Called to determine the type (if any) of foundation to draw for industry tile.
@ CBID_INDUSTRY_PRODUCTION_CHANGE
Called on production changes, so it can be adjusted.
@ CBID_INDUSTRY_MONTHLYPROD_CHANGE
Called monthly on production changes, so it can be adjusted more frequently.
@ CBID_INDUSTRY_PROD_CHANGE_BUILD
Called when industry is built to set initial production level.
@ CBID_INDTILE_CARGO_ACCEPTANCE
Called to query the cargo acceptance of the industry tile.
@ CBID_INDTILE_ACCEPT_CARGO
Called to determine which cargoes an industry should accept.
@ CBID_INDUSTRY_INPUT_CARGO_TYPES
Customize the input cargo types of a newly build industry.
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
@ ShapeCheck
decides slope suitability
@ AcceptCargo
decides accepted types
@ CargoAcceptance
decides amount of cargo acceptance
@ DrawFoundations
decides if default foundations need to be drawn
@ Autoslope
decides allowance of autosloping
CargoType GetCargoTranslation(uint8_t cargo, const GRFFile *grffile, bool usebit)
Translate a GRF-local cargo slot/bitnum into a CargoType.
Cargo support for NewGRFs.
bool ConvertBooleanCallback(const GRFFile *grffile, uint16_t cbid, uint16_t cb_res)
Converts a callback result into a boolean.
void ErrorUnknownCallbackResult(GrfID grfid, uint16_t cbid, uint16_t cb_res)
Record that a NewGRF returned an unknown/invalid callback result.
GRFConfig * GetGRFConfig(GrfID 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.
@ UserCreation
from the Fund/build window
@ MapGeneration
during random map generation
@ ProspectCreation
from the Fund/build using prospecting
@ RandomCreation
during creation of random ingame industry
void TriggerIndustryTileRandomisation(TileIndex tile, IndustryRandomTrigger trigger)
Trigger a random trigger for a single industry tile.
CommandCost PerformIndustryTileSlopeCheck(TileIndex ind_base_tile, TileIndex ind_tile, const IndustryTileSpec *its, IndustryType type, IndustryGfx gfx, size_t layout_index, uint16_t initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type)
Check the slope of a tile of a new industry.
void TriggerIndustryRandomisation(Industry *ind, IndustryRandomTrigger trigger)
Trigger a random trigger for all industry tiles.
NewGRF handling of industry tiles.
StrongType::Typedef< uint32_t, struct GRFStringIDTag, StrongType::Compare, StrongType::Integer > GRFStringID
Type for GRF-internal string IDs.
Functions related to news.
void DeleteIndustryNews(IndustryID iid)
Remove news regarding given industry.
NewsType
Type of news.
Definition news_type.h:29
@ IndustryCompany
Production changes of industry serviced by local company.
Definition news_type.h:38
@ IndustryClose
Closing of industries.
Definition news_type.h:36
@ IndustryOpen
Opening of industries.
Definition news_type.h:35
@ IndustryNobody
Other industry production changes.
Definition news_type.h:40
@ IndustryOther
Production changes of industry serviced by competitor(s).
Definition news_type.h:39
Base for all objects.
@ Editor
In the scenario editor.
Definition openttd.h:21
@ Transfer
Transfer all cargo onto the platform.
Definition order_type.h:70
@ Unload
Force unloading all cargo onto the platform, possibly not getting paid.
Definition order_type.h:69
Some methods of Pool are placed here in order to reduce compilation time and binary size.
#define INSTANTIATE_POOL_METHODS(name)
Force instantiation of pool methods so we don't get linker errors.
uint32_t RandomRange(uint32_t limit, const std::source_location location=std::source_location::current())
Pick a random number between 0 and limit - 1, inclusive.
bool Chance16I(const uint32_t a, const uint32_t b, const uint32_t r)
Checks if a given randomize-number is below a given probability.
bool Chance16(const uint32_t a, const uint32_t b, const std::source_location location=std::source_location::current())
Flips a coin with given probability.
bool Chance16R(const uint32_t a, const uint32_t b, uint32_t &r, const std::source_location location=std::source_location::current())
Flips a coin with a given probability and saves the randomize-number in a variable.
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
IndustryDensity
Available industry map generation densities.
@ FundedOnly
The game does not build industries.
@ End
Number of industry density settings.
@ VeryLow
Very few industries at game start.
@ Custom
Custom number of industries.
static constexpr int GetSlopeMaxZ(Slope s)
Returns the height of the highest corner of a slope relative to TileZ (= minimal height).
Definition slope_func.h:170
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:377
Slope ComplementSlope(Slope s)
Return the complement of a slope.
Definition slope_func.h:86
Slope
Enumeration for the slope-type.
Definition slope_type.h:53
@ SLOPE_W
the west corner of the tile is raised
Definition slope_type.h:55
@ SLOPE_E
the east corner of the tile is raised
Definition slope_type.h:57
@ SLOPE_S
the south corner of the tile is raised
Definition slope_type.h:56
@ SLOPE_N
the north corner of the tile is raised
Definition slope_type.h:58
@ SLOPE_SW
south and west corner are raised
Definition slope_type.h:61
@ SLOPE_FLAT
a flat tile
Definition slope_type.h:54
@ SLOPE_NE
north and east corner are raised
Definition slope_type.h:63
@ SLOPE_SE
south and east corner are raised
Definition slope_type.h:62
@ SLOPE_NW
north and west corner are raised
Definition slope_type.h:60
Foundation
Enumeration for Foundations.
Definition slope_type.h:119
@ Leveled
The tile is leveled up to a flat slope.
Definition slope_type.h:121
@ None
The tile has no foundation, the slope remains unchanged.
Definition slope_type.h:120
Functions related to sound.
SoundFx
Sound effects from baseset.
Definition sound_type.h:46
@ SND_30_TOFFEE_QUARRY
48 == 0x30 Industry animation: toffee quarry: drill
Definition sound_type.h:96
@ SND_2E_BUBBLE_GENERATOR
46 == 0x2E Industry animation: bubble generator (1): generate bubble
Definition sound_type.h:94
@ SND_2D_SUGAR_MINE_1
45 == 0x2D Industry animation: sugar mine (1): shaking sieve
Definition sound_type.h:93
@ SND_2B_TOY_FACTORY_2
43 == 0x2B Industry animation: toy factory (2): stamp product
Definition sound_type.h:91
@ SND_38_LUMBER_MILL_1
56 == 0x38 Industry animation: lumber mill (1): chainsaw
Definition sound_type.h:104
@ SND_29_SUGAR_MINE_2
41 == 0x29 Industry animation: sugar mine (2): shaking sieve
Definition sound_type.h:89
@ SND_2C_TOY_FACTORY_1
44 == 0x2C Industry animation: toy factory (1): conveyor belt
Definition sound_type.h:92
@ SND_37_LUMBER_MILL_2
55 == 0x37 Industry animation: lumber mill (2): falling tree
Definition sound_type.h:103
@ SND_0C_POWER_STATION
10 == 0x0A Industry animation: power station: spark
Definition sound_type.h:58
@ SND_0B_MINE
9 == 0x09 Industry animation: coal/copper/gold mine: headgear
Definition sound_type.h:57
@ SND_36_LUMBER_MILL_3
54 == 0x36 Industry animation: lumber mill (3): crashing tree
Definition sound_type.h:102
@ SND_2A_TOY_FACTORY_3
42 == 0x2A Industry animation: toy factory (3): eject product
Definition sound_type.h:90
@ Industry
Source/destination is an industry.
Definition source_type.h:21
static PaletteID GetColourPalette(Colours colour)
Get recolour palette for a colour.
Definition sprite.h:221
PaletteID SpriteLayoutPaletteTransform(SpriteID image, PaletteID pal, PaletteID default_pal)
Applies PALETTE_MODIFIER_TRANSPARENT and PALETTE_MODIFIER_COLOUR to a palette entry of a sprite layou...
Definition sprite.h:188
PaletteID GroundSpritePaletteTransform(SpriteID image, PaletteID pal, PaletteID default_pal)
Applies PALETTE_MODIFIER_COLOUR to a palette entry of a ground sprite.
Definition sprite.h:207
static const SpriteID SPR_IT_TOY_FACTORY_STAMP_HOLDER
Definition sprites.h:1310
static const SpriteID SPR_IT_TOY_FACTORY_ROBOT
Definition sprites.h:1313
static const SpriteID SPR_IT_TOY_FACTORY_CLAY
Definition sprites.h:1312
static const SpriteID SPR_IT_POWER_PLANT_TRANSFORMERS
Definition sprites.h:1314
static const SpriteID SPR_IT_BUBBLE_GENERATOR_SPRING
Definition sprites.h:1308
static const SpriteID SPR_IT_SUGAR_MINE_PILE
Definition sprites.h:1305
static const SpriteID SPR_FLAT_WATER_TILE
Definition sprites.h:684
static const SpriteID SPR_IT_BUBBLE_GENERATOR_BUBBLE
Definition sprites.h:1309
static const SpriteID SPR_IT_TOFFEE_QUARRY_TOFFEE
Definition sprites.h:1306
static const SpriteID SPR_IT_TOFFEE_QUARRY_SHOVEL
Definition sprites.h:1307
static const SpriteID SPR_IT_SUGAR_MINE_SIEVE
Definition sprites.h:1303
static const SpriteID SPR_IT_SUGAR_MINE_CLOUDS
Definition sprites.h:1304
static const SpriteID SPR_IT_TOY_FACTORY_STAMP
Definition sprites.h:1311
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:261
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.
StrongType::Typedef< uint32_t, struct StringIDTag, StrongType::Compare, StrongType::Integer > StringID
Numeric value that represents a string, independent of the selected language.
static constexpr 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...
const T & GetOriginalValue() const
Returns the backupped value.
VehicleType type
Type of vehicle.
Class for storing amounts of cargo.
Definition cargo_type.h:118
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:141
This structure is the same for both Industries and Houses.
Definition sprite.h:90
uint8_t draw_proc
This allows to specify a special drawing procedure.
Definition sprite.h:93
This is used to gather some data about animation drawing in the industry code Image_1-2-3 are in fact...
uint8_t image_1
image offset 1
uint8_t image_3
image offset 3
uint8_t image_2
image offset 2
int x
coordinate x of the first image offset
A special vehicle is one of the following:
uint8_t animation_substate
Sub state to time the change of the graphics/behaviour.
std::string GetName() const
Get the name of this grf.
GrfID grfid
grfid that introduced this entity.
const struct GRFFile * grffile
grf file that introduced this entity
bool HasGrfFile() const
Test if this entity was introduced by NewGRF.
Data for managing the number and type of industries in the game.
Definition industry.h:309
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:311
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:310
Defines the data structure for constructing industry.
IndustryCallbackMasks callback_mask
Bitmask of industry callbacks that have to be called.
bool IsProcessingIndustry() const
Is an industry with the spec a processing industry?
std::vector< uint8_t > random_sounds
Random sounds;.
Money GetRemovalCost() const
Get the cost for removing this industry Take note that the cost will always be zero for non-grf indus...
std::array< CargoType, INDUSTRY_NUM_INPUTS > accepts_cargo
16 accepted cargoes.
uint8_t appear_creation[NUM_LANDSCAPE]
Probability of appearance during map creation.
bool UsesOriginalEconomy() const
Determines whether this industrytype uses standard/newgrf production changes.
uint8_t minimal_cargo
minimum amount of cargo transported to the stations.
uint32_t removal_cost_multiplier
Base removal cost multiplier.
uint32_t prospecting_chance
Chance prospecting succeeds.
StringID production_up_text
Message appearing when the industry's production is increasing.
SubstituteGRFFileProps grf_prop
properties related to the grf file
StringID name
Displayed name of the industry.
bool IsRawIndustry() const
Is an industry with the spec a raw industry?
IndustryType conflicting[3]
Industries this industry cannot be close to.
uint8_t appear_ingame[NUM_LANDSCAPE]
Probability of appearance in game.
StringID production_down_text
Message appearing when the industry's production is decreasing.
IndustryBehaviours behaviour
How this industry will behave, and how others entities can use it.
StringID closure_text
Message appearing when the industry closes.
StringID new_industry_text
Message appearing when the industry is built.
std::vector< IndustryTileLayout > layouts
List of possible tile layouts for the industry.
bool enabled
entity still available (by default true).newgrf can disable it, though
Money GetConstructionCost() const
Get the cost for constructing this industry.
IndustryLifeTypes life_type
This is also known as Industry production flag, in newgrf specs.
IndustryCheck 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:294
uint32_t probability
Relative probability of building this industry.
Definition industry.h:295
uint16_t target_count
Desired number of industries of this type.
Definition industry.h:297
uint8_t min_number
Smallest number of industries that should exist (either 0 or 1).
Definition industry.h:296
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:299
uint16_t max_wait
Starting number of turns to wait (copied to wait_count).
Definition industry.h:298
CargoType cargo
Cargo type.
Definition industry.h:88
CargoType cargo
Cargo type.
Definition industry.h:76
HistoryData< ProducedHistory > history
History of cargo produced and transported for this month and 24 previous months.
Definition industry.h:79
uint8_t rate
Production rate.
Definition industry.h:78
Defines the internal data of a functional industry.
Definition industry.h:64
static Industry * GetRandom()
Return a random valid industry.
IndustryType type
type of industry.
Definition industry.h:117
Owner exclusive_supplier
Which company has exclusive rights to deliver cargo (INVALID_OWNER = anyone).
Definition industry.h:132
TimerGameCalendar::Date construction_date
Date of the construction of the industry.
Definition industry.h:129
IndustryControlFlags ctlflags
flags overriding standard behaviours
Definition industry.h:122
bool IsCargoAccepted() const
Test if this industry accepts any cargo.
Definition industry.h:225
PersistentStorage * psa
Persistent storage for NewGRF industries.
Definition industry.h:138
uint8_t prod_level
general production level
Definition industry.h:114
Colours random_colour
randomized colour of the industry, for display purpose
Definition industry.h:119
void RecomputeProductionMultipliers()
Recompute production_rate for current prod_level.
EncodedString text
General text with additional information.
Definition industry.h:134
std::string cached_name
NOSAVE: Cache of the resolved name of the industry.
Definition industry.h:126
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:160
ValidHistoryMask valid_history
Mask of valid history records.
Definition industry.h:111
TimerGameEconomy::Year last_prod_year
last economy year of production
Definition industry.h:120
ProducedCargoes produced
produced cargo slots
Definition industry.h:112
uint16_t random
Random value used for randomisation of all kinds of things.
Definition industry.h:136
static void PostDestructor(size_t index)
Invalidating some stuff after removing item from the pool.
Town * town
Nearest town.
Definition industry.h:109
Owner founder
Founder of the industry.
Definition industry.h:128
uint8_t selected_layout
Which tile layout was used when creating the industry.
Definition industry.h:131
AcceptedCargoes accepted
accepted cargo slots
Definition industry.h:113
static uint16_t GetIndustryTypeCount(IndustryType type)
Get the count of industries for this type.
Definition industry.h:267
Owner owner
owner of the industry. Which SHOULD always be (imho) OWNER_NONE
Definition industry.h:118
static Industry * GetByTile(TileIndex tile)
Get the industry of the given tile.
Definition industry.h:253
TileArea location
Location of the industry.
Definition industry.h:108
Station * neutral_station
Associated neutral station.
Definition industry.h:110
~Industry()
Remove any reference to this industry from the game.
IndustryConstructionType construction_type
Way the industry was constructed (.
Definition industry.h:130
StationList stations_near
NOSAVE: List of nearby stations.
Definition industry.h:125
bool IsCargoProduced() const
Test if this industry produces any cargo.
Definition industry.h:231
Owner exclusive_consumer
Which company has exclusive rights to take cargo (INVALID_OWNER = anyone).
Definition industry.h:133
uint16_t counter
used for animation and/or production (if available cargo)
Definition industry.h:115
uint8_t was_cargo_delivered
flag that indicate this has been the closest industry chosen for cargo delivery by a station....
Definition industry.h:121
bool TileBelongsToIndustry(TileIndex tile) const
Check if a given tile belongs to this industry.
Definition industry.h:150
static std::array< FlatSet< IndustryID >, NUM_INDUSTRYTYPES > industries
List of industries of each type.
Definition industry.h:279
static uint SizeX()
Get the size of the map along the X.
Definition map_func.h:262
static TileIndex WrapToMap(TileIndex tile)
'Wraps' the given "tile" so it is within the map.
Definition map_func.h:320
static uint ScaleBySize(uint n)
Scales the given value by the map size, where the given value is for a 256 by 256 map.
Definition map_func.h:331
static uint SizeY()
Get the size of the map along the Y.
Definition map_func.h:271
static uint ScaleByLandProportion(uint n)
Scales the given value by the number of water tiles.
Definition map_func.h:308
static uint ScaleBySize1D(uint n)
Scales the given value by the maps circumference, where the given value is for a 256 by 256 map.
Definition map_func.h:344
static uint MaxY()
Gets the maximum Y coordinate within the map, including TileType::Void.
Definition map_func.h:298
static uint MaxX()
Gets the maximum X coordinate within the map, including TileType::Void.
Definition map_func.h:289
static uint Size()
Get the size of the map.
Definition map_func.h:280
If you change this, keep in mind that it is also saved in 2 other places:
Definition order_base.h:34
uint16_t w
The width of the area.
void Add(TileIndex to_add)
Add a single tile to a tile area; enlarge if needed.
Definition tilearea.cpp:43
TileIndex tile
The base tile of the area.
uint16_t h
The height of the area.
OrthogonalTileArea & Expand(int rad)
Expand a tile area by rad tiles in each direction, keeping within map bounds.
Definition tilearea.cpp:123
SpriteID sprite
The 'real' sprite.
Definition gfx_type.h:23
PaletteID pal
The palette (use PAL_NONE) if not needed).
Definition gfx_type.h:24
static Pool::IterateWrapper< Industry > Iterate(size_t from=0)
static T * Create(Targs &&... args)
static Industry * Get(auto index)
static Industry * GetIfValid(auto index)
static constexpr size_t MAX_SIZE
Structure to encapsulate the pseudo random number generators.
void SetSeed(uint32_t seed)
(Re)set the state of the random number generator.
uint32_t Next()
Generate the next pseudo random number.
A location from where cargo can come from (or go to).
Definition source_type.h:32
static Station * Get(auto index)
T * Next() const
Get next vehicle in the chain.
bool HasSpriteGroups() const
Check whether the entity has sprite groups.
Station data structure.
IndustryList industries_near
Cached list of industries near the station that can accept cargo,.
uint16_t subst_id
The id of the entity to replace.
Tile description for the 'land area information' tool.
Definition tile_cmd.h:40
std::optional< std::string > grf
newGRF used for the tile contents
Definition tile_cmd.h:51
StringID str
Description of the tile.
Definition tile_cmd.h:41
std::array< Owner, 4 > owner
Name of the owner(s).
Definition tile_cmd.h:43
uint64_t dparam
Parameter of the str string.
Definition tile_cmd.h:42
Tile information, used while rendering the tile.
Definition tile_cmd.h:34
Slope tileh
Slope of the tile.
Definition tile_cmd.h:35
TileIndex tile
Tile index.
Definition tile_cmd.h:36
Set of callback functions for performing tile operations of a given tile type.
Definition tile_cmd.h:214
uint32_t population
Current population of people.
Definition town.h:54
Town data structure.
Definition town.h:64
TileIndex xy
town center tile
Definition town.h:65
TownCache cache
Container for all cacheable data.
Definition town.h:67
Vehicle data structure.
CargoType cargo_type
type of cargo this vehicle is carrying
bool IsFrontEngine() const
Check if the vehicle is a front engine.
Owner owner
Which company owns the vehicle?
void DeleteSubsidyWith(Source source)
Delete the subsidies associated with a given cargo source type and id.
Definition subsidy.cpp:120
Functions related to subsidies.
Command definitions related to terraforming.
bool IsTileFlat(TileIndex tile, int *h)
Check if a given tile is flat.
Definition tile_map.cpp:94
int GetTileMaxZ(TileIndex t)
Get top height of the tile inside the map.
Definition tile_map.cpp:135
int GetTileZ(TileIndex tile)
Get bottom height of the tile.
Definition tile_map.cpp:115
static bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
static uint TileHeight(Tile tile)
Returns the height of a tile.
Definition tile_map.h:29
int GetTileMaxPixelZ(TileIndex tile)
Get top height of the tile.
Definition tile_map.h:312
uint8_t GetAnimationFrame(Tile t)
Get the current animation frame.
Definition tile_map.h:250
bool IsValidTile(Tile tile)
Checks if a tile is valid.
Definition tile_map.h:161
TropicZone GetTropicZone(Tile tile)
Get the tropic zone.
Definition tile_map.h:238
void SetAnimationFrame(Tile t, uint8_t frame)
Set a new animation frame.
Definition tile_map.h:262
Slope GetTileSlope(TileIndex tile)
Return the slope of a given tile inside the map.
Definition tile_map.h:279
static TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition tile_map.h:96
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
@ Desert
Tile is desert.
Definition tile_type.h:83
@ Rainforest
Rainforest tile.
Definition tile_type.h:84
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:100
static constexpr uint TILE_SIZE
Tile size in world coordinates.
Definition tile_type.h:15
@ Station
A tile of a station or airport.
Definition tile_type.h:54
@ Industry
Part of an industry.
Definition tile_type.h:57
@ Void
Invisible tiles at the SW and SE border.
Definition tile_type.h:56
@ Trees
Tile with one or more trees.
Definition tile_type.h:53
@ House
A house by a town.
Definition tile_type.h:52
@ Clear
A tile without any structures, i.e. grass, rocks, farm fields etc.
Definition tile_type.h:49
OrthogonalTileArea TileArea
Shorthand for the much more common orthogonal tile area.
Definition of Interval and OneShot timers.
Definition of the game-calendar-timer.
Definition of the game-economy-timer.
Definition of the tick-based game-timer.
Base of the town class.
Town * ClosestTownFromTile(TileIndex tile, uint threshold)
Return the town closest (in distance or ownership) to a given tile, within a given threshold.
bool IsTransparencySet(TransparencyOption to)
Check if the transparency option bit is set and if we aren't in the game menu (there's never transpar...
bool IsInvisibilitySet(TransparencyOption to)
Check if the invisibility option bit is set and if we aren't in the game menu (there's never transpar...
@ Industries
industries
Map accessors for tree tiles.
TreeGrowthStage GetTreeGrowth(Tile t)
Returns the tree growth stage.
Definition tree_map.h:196
TreeGround GetTreeGround(Tile t)
Returns the groundtype for tree tiles.
Definition tree_map.h:102
@ Shore
Shore.
Definition tree_map.h:56
@ Rough
Rough land.
Definition tree_map.h:54
@ Grown
Fully grown tree.
Definition tree_map.h:69
CommandCost EnsureNoVehicleOnGround(TileIndex tile)
Ensure there is no vehicle at the ground at the given position.
Definition vehicle.cpp:558
Functions related to vehicles.
@ Ship
Ship vehicle type.
@ Aircraft
Aircraft vehicle type.
@ Road
Road vehicle type.
@ 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:664
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:826
void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub, int extra_offs_x, int extra_offs_y)
Draws a ground sprite for the current tile.
Definition viewport.cpp:579
Functions related to (drawing on) viewports.
Functions related to water management.
void TileLoop_Water(TileIndex tile)
Tile callback function signature for running periodic tile updates.
bool IsTileOnWater(Tile t)
Tests if the tile was built on water.
Definition water_map.h:138
WaterClass
classes of water (for WaterTileType::Clear water tile type).
Definition water_map.h:39
@ Invalid
Used for industry tiles on land (also for oilrig if newgrf says so).
Definition water_map.h:43
bool HasTileWaterClass(Tile t)
Checks whether the tile has an waterclass associated.
Definition water_map.h:103
WaterClass GetWaterClass(Tile t)
Get the water class at a tile.
Definition water_map.h:114
bool IsWaterTile(Tile t)
Is it a water tile with plain water?
Definition water_map.h:192
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Definition window.cpp:1204
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:3318
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting).
Definition window.cpp:3196
Window functions not directly related to making/drawing windows.