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