Maintain a circular buffer of recent commands, add to crashlog.
[openttd-joker.git] / src / industry_cmd.cpp
blob5489e18a1bbc1f0b1c6c6c16e85994a358a1c58a
1 /* $Id$ */
3 /*
4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
8 */
10 /** @file industry_cmd.cpp Handling of industry tiles. */
12 #include "stdafx.h"
13 #include "clear_map.h"
14 #include "industry.h"
15 #include "station_base.h"
16 #include "landscape.h"
17 #include "viewport_func.h"
18 #include "command_func.h"
19 #include "town.h"
20 #include "news_func.h"
21 #include "cheat_type.h"
22 #include "genworld.h"
23 #include "tree_map.h"
24 #include "newgrf_cargo.h"
25 #include "newgrf_debug.h"
26 #include "newgrf_industrytiles.h"
27 #include "autoslope.h"
28 #include "water.h"
29 #include "strings_func.h"
30 #include "window_func.h"
31 #include "date_func.h"
32 #include "vehicle_func.h"
33 #include "sound_func.h"
34 #include "animated_tile_func.h"
35 #include "effectvehicle_func.h"
36 #include "effectvehicle_base.h"
37 #include "ai/ai.hpp"
38 #include "core/pool_func.hpp"
39 #include "subsidy_func.h"
40 #include "core/backup_type.hpp"
41 #include "object_base.h"
42 #include "game/game.hpp"
43 #include "error.h"
45 #include "table/strings.h"
46 #include "table/industry_land.h"
47 #include "table/build_industry.h"
49 #include "safeguards.h"
51 IndustryPool _industry_pool("Industry");
52 INSTANTIATE_POOL_METHODS(Industry)
54 void ShowIndustryViewWindow(int industry);
55 void BuildOilRig(TileIndex tile);
57 static byte _industry_sound_ctr;
58 static TileIndex _industry_sound_tile;
60 uint16 Industry::counts[NUM_INDUSTRYTYPES];
62 IndustrySpec _industry_specs[NUM_INDUSTRYTYPES];
63 IndustryTileSpec _industry_tile_specs[NUM_INDUSTRYTILES];
64 IndustryBuildData _industry_builder; ///< In-game manager of industries.
66 /**
67 * This function initialize the spec arrays of both
68 * industry and industry tiles.
69 * It adjusts the enabling of the industry too, based on climate availability.
70 * This will allow for clearer testings
72 void ResetIndustries()
74 memset(&_industry_specs, 0, sizeof(_industry_specs));
75 memcpy(&_industry_specs, &_origin_industry_specs, sizeof(_origin_industry_specs));
77 /* once performed, enable only the current climate industries */
78 for (IndustryType i = 0; i < NUM_INDUSTRYTYPES; i++) {
79 _industry_specs[i].enabled = i < NEW_INDUSTRYOFFSET &&
80 HasBit(_origin_industry_specs[i].climate_availability, _settings_game.game_creation.landscape);
83 memset(&_industry_tile_specs, 0, sizeof(_industry_tile_specs));
84 memcpy(&_industry_tile_specs, &_origin_industry_tile_specs, sizeof(_origin_industry_tile_specs));
86 /* Reset any overrides that have been set. */
87 _industile_mngr.ResetOverride();
88 _industry_mngr.ResetOverride();
91 /**
92 * Retrieve the type for this industry. Although it is accessed by a tile,
93 * it will return the general type of industry, and not the sprite index
94 * as would do GetIndustryGfx.
95 * @param tile that is queried
96 * @pre IsTileType(tile, MP_INDUSTRY)
97 * @return general type for this industry, as defined in industry.h
99 IndustryType GetIndustryType(TileIndex tile)
101 assert(IsTileType(tile, MP_INDUSTRY));
103 const Industry *ind = Industry::GetByTile(tile);
104 assert(ind != NULL);
105 return ind->type;
109 * Accessor for array _industry_specs.
110 * This will ensure at once : proper access and
111 * not allowing modifications of it.
112 * @param thistype of industry (which is the index in _industry_specs)
113 * @pre thistype < NUM_INDUSTRYTYPES
114 * @return a pointer to the corresponding industry spec
116 const IndustrySpec *GetIndustrySpec(IndustryType thistype)
118 assert(thistype < NUM_INDUSTRYTYPES);
119 return &_industry_specs[thistype];
123 * Accessor for array _industry_tile_specs.
124 * This will ensure at once : proper access and
125 * not allowing modifications of it.
126 * @param gfx of industrytile (which is the index in _industry_tile_specs)
127 * @pre gfx < INVALID_INDUSTRYTILE
128 * @return a pointer to the corresponding industrytile spec
130 const IndustryTileSpec *GetIndustryTileSpec(IndustryGfx gfx)
132 assert(gfx < INVALID_INDUSTRYTILE);
133 return &_industry_tile_specs[gfx];
136 Industry::~Industry()
138 if (CleaningPool()) return;
140 /* Industry can also be destroyed when not fully initialized.
141 * This means that we do not have to clear tiles either.
142 * Also we must not decrement industry counts in that case. */
143 if (this->location.w == 0) return;
145 TILE_AREA_LOOP(tile_cur, this->location) {
146 if (IsTileType(tile_cur, MP_INDUSTRY)) {
147 if (GetIndustryIndex(tile_cur) == this->index) {
148 DeleteNewGRFInspectWindow(GSF_INDUSTRYTILES, tile_cur);
150 /* MakeWaterKeepingClass() can also handle 'land' */
151 MakeWaterKeepingClass(tile_cur, OWNER_NONE);
153 } else if (IsTileType(tile_cur, MP_STATION) && IsOilRig(tile_cur)) {
154 DeleteOilRig(tile_cur);
158 if (GetIndustrySpec(this->type)->behaviour & INDUSTRYBEH_PLANT_FIELDS) {
159 TileArea ta(this->location.tile - TileDiffXY(min(TileX(this->location.tile), 21), min(TileY(this->location.tile), 21)), 42, 42);
160 ta.ClampToMap();
162 /* Remove the farmland and convert it to regular tiles over time. */
163 TILE_AREA_LOOP(tile_cur, ta) {
164 if (IsTileType(tile_cur, MP_CLEAR) && IsClearGround(tile_cur, CLEAR_FIELDS) &&
165 GetIndustryIndexOfField(tile_cur) == this->index) {
166 SetIndustryIndexOfField(tile_cur, INVALID_INDUSTRY);
171 /* don't let any disaster vehicle target invalid industry */
172 ReleaseDisastersTargetingIndustry(this->index);
174 /* Clear the persistent storage. */
175 delete this->psa;
177 DecIndustryTypeCount(this->type);
179 DeleteIndustryNews(this->index);
180 DeleteWindowById(WC_INDUSTRY_VIEW, this->index);
181 DeleteNewGRFInspectWindow(GSF_INDUSTRIES, this->index);
183 DeleteSubsidyWith(ST_INDUSTRY, this->index);
184 CargoPacket::InvalidateAllFrom(ST_INDUSTRY, this->index);
188 * Invalidating some stuff after removing item from the pool.
189 * @param index index of deleted item
191 void Industry::PostDestructor(size_t index)
193 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0);
194 Station::RecomputeIndustriesNearForAll();
199 * Return a random valid industry.
200 * @return random industry, NULL if there are no industries
202 /* static */ Industry *Industry::GetRandom()
204 if (Industry::GetNumItems() == 0) return NULL;
205 int num = RandomRange((uint16)Industry::GetNumItems());
206 size_t index = MAX_UVALUE(size_t);
208 while (num >= 0) {
209 num--;
210 index++;
212 /* Make sure we have a valid industry */
213 while (!Industry::IsValidID(index)) {
214 index++;
215 assert(index < Industry::GetPoolSize());
219 return Industry::Get(index);
223 static void IndustryDrawSugarMine(const TileInfo *ti)
225 if (!IsIndustryCompleted(ti->tile)) return;
227 const DrawIndustryAnimationStruct *d = &_draw_industry_spec1[GetAnimationFrame(ti->tile)];
229 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_SIEVE + d->image_1, PAL_NONE, d->x, 0);
231 if (d->image_2 != 0) {
232 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_CLOUDS + d->image_2 - 1, PAL_NONE, 8, 41);
235 if (d->image_3 != 0) {
236 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_PILE + d->image_3 - 1, PAL_NONE,
237 _drawtile_proc1[d->image_3 - 1].x, _drawtile_proc1[d->image_3 - 1].y);
241 static void IndustryDrawToffeeQuarry(const TileInfo *ti)
243 uint8 x = 0;
245 if (IsIndustryCompleted(ti->tile)) {
246 x = _industry_anim_offs_toffee[GetAnimationFrame(ti->tile)];
247 if (x == 0xFF) {
248 x = 0;
252 AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_SHOVEL, PAL_NONE, 22 - x, 24 + x);
253 AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_TOFFEE, PAL_NONE, 6, 14);
256 static void IndustryDrawBubbleGenerator( const TileInfo *ti)
258 if (IsIndustryCompleted(ti->tile)) {
259 AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_BUBBLE, PAL_NONE, 5, _industry_anim_offs_bubbles[GetAnimationFrame(ti->tile)]);
261 AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_SPRING, PAL_NONE, 3, 67);
264 static void IndustryDrawToyFactory(const TileInfo *ti)
266 const DrawIndustryAnimationStruct *d = &_industry_anim_offs_toys[GetAnimationFrame(ti->tile)];
268 if (d->image_1 != 0xFF) {
269 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_CLAY, PAL_NONE, d->x, 96 + d->image_1);
272 if (d->image_2 != 0xFF) {
273 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_ROBOT, PAL_NONE, 16 - d->image_2 * 2, 100 + d->image_2);
276 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP, PAL_NONE, 7, d->image_3);
277 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP_HOLDER, PAL_NONE, 0, 42);
280 static void IndustryDrawCoalPlantSparks(const TileInfo *ti)
282 if (IsIndustryCompleted(ti->tile)) {
283 uint8 image = GetAnimationFrame(ti->tile);
285 if (image != 0 && image < 7) {
286 AddChildSpriteScreen(image + SPR_IT_POWER_PLANT_TRANSFORMERS,
287 PAL_NONE,
288 _coal_plant_sparks[image - 1].x,
289 _coal_plant_sparks[image - 1].y
295 typedef void IndustryDrawTileProc(const TileInfo *ti);
296 static IndustryDrawTileProc * const _industry_draw_tile_procs[5] = {
297 IndustryDrawSugarMine,
298 IndustryDrawToffeeQuarry,
299 IndustryDrawBubbleGenerator,
300 IndustryDrawToyFactory,
301 IndustryDrawCoalPlantSparks,
304 static void DrawTile_Industry(TileInfo *ti)
306 IndustryGfx gfx = GetIndustryGfx(ti->tile);
307 Industry *ind = Industry::GetByTile(ti->tile);
308 const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
310 /* Retrieve pointer to the draw industry tile struct */
311 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
312 /* Draw the tile using the specialized method of newgrf industrytile.
313 * DrawNewIndustry will return false if ever the resolver could not
314 * find any sprite to display. So in this case, we will jump on the
315 * substitute gfx instead. */
316 if (indts->grf_prop.spritegroup[0] != NULL && DrawNewIndustryTile(ti, ind, gfx, indts)) {
317 return;
318 } else {
319 /* No sprite group (or no valid one) found, meaning no graphics associated.
320 * Use the substitute one instead */
321 if (indts->grf_prop.subst_id != INVALID_INDUSTRYTILE) {
322 gfx = indts->grf_prop.subst_id;
323 /* And point the industrytile spec accordingly */
324 indts = GetIndustryTileSpec(gfx);
329 const DrawBuildingsTileStruct *dits = &_industry_draw_tile_data[gfx << 2 | (indts->anim_state ?
330 GetAnimationFrame(ti->tile) & INDUSTRY_COMPLETED :
331 GetIndustryConstructionStage(ti->tile))];
333 SpriteID image = dits->ground.sprite;
335 /* DrawFoundation() modifies ti->z and ti->tileh */
336 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
338 /* If the ground sprite is the default flat water sprite, draw also canal/river borders.
339 * Do not do this if the tile's WaterClass is 'land'. */
340 if (image == SPR_FLAT_WATER_TILE && IsTileOnWater(ti->tile)) {
341 DrawWaterClassGround(ti);
342 } else {
343 DrawGroundSprite(image, GroundSpritePaletteTransform(image, dits->ground.pal, GENERAL_SPRITE_COLOUR(ind->random_colour)));
346 DrawOverlay(ti, MP_INDUSTRY);
348 /* If industries are transparent and invisible, do not draw the upper part */
349 if (IsInvisibilitySet(TO_INDUSTRIES)) return;
351 /* Add industry on top of the ground? */
352 image = dits->building.sprite;
353 if (image != 0) {
354 AddSortableSpriteToDraw(image, SpriteLayoutPaletteTransform(image, dits->building.pal, GENERAL_SPRITE_COLOUR(ind->random_colour)),
355 ti->x + dits->subtile_x,
356 ti->y + dits->subtile_y,
357 dits->width,
358 dits->height,
359 dits->dz,
360 ti->z,
361 IsTransparencySet(TO_INDUSTRIES));
363 if (IsTransparencySet(TO_INDUSTRIES)) return;
367 int proc = dits->draw_proc - 1;
368 if (proc >= 0) _industry_draw_tile_procs[proc](ti);
372 static int GetSlopePixelZ_Industry(TileIndex tile, uint x, uint y)
374 return GetTileMaxPixelZ(tile);
377 static Foundation GetFoundation_Industry(TileIndex tile, Slope tileh)
379 IndustryGfx gfx = GetIndustryGfx(tile);
381 /* For NewGRF industry tiles we might not be drawing a foundation. We need to
382 * account for this, as other structures should
383 * draw the wall of the foundation in this case.
385 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
386 const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
387 if (indts->grf_prop.spritegroup[0] != NULL && HasBit(indts->callback_mask, CBM_INDT_DRAW_FOUNDATIONS)) {
388 uint32 callback_res = GetIndustryTileCallback(CBID_INDTILE_DRAW_FOUNDATIONS, 0, 0, gfx, Industry::GetByTile(tile), tile);
389 if (callback_res != CALLBACK_FAILED && !ConvertBooleanCallback(indts->grf_prop.grffile, CBID_INDTILE_DRAW_FOUNDATIONS, callback_res)) return FOUNDATION_NONE;
392 return FlatteningFoundation(tileh);
395 static void AddAcceptedCargo_Industry(TileIndex tile, CargoArray &acceptance, uint32 *always_accepted)
397 IndustryGfx gfx = GetIndustryGfx(tile);
398 const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
400 /* When we have to use a callback, we put our data in the next two variables */
401 CargoID raw_accepts_cargo[lengthof(itspec->accepts_cargo)];
402 uint8 raw_cargo_acceptance[lengthof(itspec->acceptance)];
404 /* And then these will always point to a same sized array with the required data */
405 const CargoID *accepts_cargo = itspec->accepts_cargo;
406 const uint8 *cargo_acceptance = itspec->acceptance;
408 if (HasBit(itspec->callback_mask, CBM_INDT_ACCEPT_CARGO)) {
409 uint16 res = GetIndustryTileCallback(CBID_INDTILE_ACCEPT_CARGO, 0, 0, gfx, Industry::GetByTile(tile), tile);
410 if (res != CALLBACK_FAILED) {
411 accepts_cargo = raw_accepts_cargo;
412 for (uint i = 0; i < lengthof(itspec->accepts_cargo); i++) raw_accepts_cargo[i] = GetCargoTranslation(GB(res, i * 5, 5), itspec->grf_prop.grffile);
416 if (HasBit(itspec->callback_mask, CBM_INDT_CARGO_ACCEPTANCE)) {
417 uint16 res = GetIndustryTileCallback(CBID_INDTILE_CARGO_ACCEPTANCE, 0, 0, gfx, Industry::GetByTile(tile), tile);
418 if (res != CALLBACK_FAILED) {
419 cargo_acceptance = raw_cargo_acceptance;
420 for (uint i = 0; i < lengthof(itspec->accepts_cargo); i++) raw_cargo_acceptance[i] = GB(res, i * 4, 4);
424 const Industry *ind = Industry::GetByTile(tile);
425 for (byte i = 0; i < lengthof(itspec->accepts_cargo); i++) {
426 CargoID a = accepts_cargo[i];
427 if (a == CT_INVALID || cargo_acceptance[i] == 0) continue; // work only with valid cargoes
429 /* Add accepted cargo */
430 acceptance[a] += cargo_acceptance[i];
432 /* Maybe set 'always accepted' bit (if it's not set already) */
433 if (HasBit(*always_accepted, a)) continue;
435 bool accepts = false;
436 for (uint cargo_index = 0; cargo_index < lengthof(ind->accepts_cargo); cargo_index++) {
437 /* Test whether the industry itself accepts the cargo type */
438 if (ind->accepts_cargo[cargo_index] == a) {
439 accepts = true;
440 break;
444 if (accepts) continue;
446 /* If the industry itself doesn't accept this cargo, set 'always accepted' bit */
447 SetBit(*always_accepted, a);
451 static void GetTileDesc_Industry(TileIndex tile, TileDesc *td)
453 const Industry *i = Industry::GetByTile(tile);
454 const IndustrySpec *is = GetIndustrySpec(i->type);
456 td->owner[0] = i->owner;
457 td->str = is->name;
458 if (!IsIndustryCompleted(tile)) {
459 SetDParamX(td->dparam, 0, td->str);
460 td->str = STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION;
463 if (is->grf_prop.grffile != NULL) {
464 td->grf = GetGRFConfig(is->grf_prop.grffile->grfid)->GetName();
468 static CommandCost ClearTile_Industry(TileIndex tile, DoCommandFlag flags)
470 Industry *i = Industry::GetByTile(tile);
471 const IndustrySpec *indspec = GetIndustrySpec(i->type);
473 /* water can destroy industries
474 * in editor you can bulldoze industries
475 * with magic_bulldozer cheat you can destroy industries
476 * (area around OILRIG is water, so water shouldn't flood it
478 if ((_current_company != OWNER_WATER && _game_mode != GM_EDITOR &&
479 !_cheats.magic_bulldozer.value) ||
480 ((flags & DC_AUTO) != 0) ||
481 (_current_company == OWNER_WATER &&
482 ((indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) ||
483 HasBit(GetIndustryTileSpec(GetIndustryGfx(tile))->slopes_refused, 5)))) {
484 SetDParam(1, indspec->name);
485 return_cmd_error(flags & DC_AUTO ? STR_ERROR_GENERIC_OBJECT_IN_THE_WAY : INVALID_STRING_ID);
488 if (flags & DC_EXEC) {
489 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index));
490 Game::NewEvent(new ScriptEventIndustryClose(i->index));
491 delete i;
493 return CommandCost(EXPENSES_CONSTRUCTION, indspec->GetRemovalCost());
497 * Move produced cargo from industry to nearby stations.
498 * @param tile Industry tile
499 * @return true if any cargo was moved.
501 static bool TransportIndustryGoods(TileIndex tile)
503 Industry *i = Industry::GetByTile(tile);
504 const IndustrySpec *indspec = GetIndustrySpec(i->type);
505 bool moved_cargo = false;
507 StationFinder stations(i->location);
509 for (uint j = 0; j < lengthof(i->produced_cargo_waiting); j++) {
510 uint cw = min(i->produced_cargo_waiting[j], 255);
511 if (cw > indspec->minimal_cargo && i->produced_cargo[j] != CT_INVALID) {
512 i->produced_cargo_waiting[j] -= cw;
514 /* fluctuating economy? */
515 if (EconomyIsInRecession()) cw = (cw + 1) / 2;
517 i->this_month_production[j] += cw;
519 uint am = MoveGoodsToStation(i->produced_cargo[j], cw, ST_INDUSTRY, i->index, stations.GetStations());
520 i->this_month_transported[j] += am;
522 moved_cargo |= (am != 0);
526 return moved_cargo;
530 static void AnimateTile_Industry(TileIndex tile)
532 IndustryGfx gfx = GetIndustryGfx(tile);
534 if (GetIndustryTileSpec(gfx)->animation.status != ANIM_STATUS_NO_ANIMATION) {
535 AnimateNewIndustryTile(tile);
536 return;
539 switch (gfx) {
540 case GFX_SUGAR_MINE_SIEVE:
541 if ((_tick_counter & 1) == 0) {
542 byte m = GetAnimationFrame(tile) + 1;
544 if (_settings_client.sound.ambient) {
545 switch (m & 7) {
546 case 2: SndPlayTileFx(SND_2D_RIP_2, tile); break;
547 case 6: SndPlayTileFx(SND_29_RIP, tile); break;
551 if (m >= 96) {
552 m = 0;
553 DeleteAnimatedTile(tile);
555 SetAnimationFrame(tile, m);
557 MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
559 break;
561 case GFX_TOFFEE_QUARY:
562 if ((_tick_counter & 3) == 0) {
563 byte m = GetAnimationFrame(tile);
565 if (_industry_anim_offs_toffee[m] == 0xFF && _settings_client.sound.ambient) {
566 SndPlayTileFx(SND_30_CARTOON_SOUND, tile);
569 if (++m >= 70) {
570 m = 0;
571 DeleteAnimatedTile(tile);
573 SetAnimationFrame(tile, m);
575 MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
577 break;
579 case GFX_BUBBLE_CATCHER:
580 if ((_tick_counter & 1) == 0) {
581 byte m = GetAnimationFrame(tile);
583 if (++m >= 40) {
584 m = 0;
585 DeleteAnimatedTile(tile);
587 SetAnimationFrame(tile, m);
589 MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
591 break;
593 /* Sparks on a coal plant */
594 case GFX_POWERPLANT_SPARKS:
595 if ((_tick_counter & 3) == 0) {
596 byte m = GetAnimationFrame(tile);
597 if (m == 6) {
598 SetAnimationFrame(tile, 0);
599 DeleteAnimatedTile(tile);
600 } else {
601 SetAnimationFrame(tile, m + 1);
602 MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
605 break;
607 case GFX_TOY_FACTORY:
608 if ((_tick_counter & 1) == 0) {
609 byte m = GetAnimationFrame(tile) + 1;
611 switch (m) {
612 case 1: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2C_MACHINERY, tile); break;
613 case 23: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2B_COMEDY_HIT, tile); break;
614 case 28: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2A_EXTRACT_AND_POP, tile); break;
615 default:
616 if (m >= 50) {
617 int n = GetIndustryAnimationLoop(tile) + 1;
618 m = 0;
619 if (n >= 8) {
620 n = 0;
621 DeleteAnimatedTile(tile);
623 SetIndustryAnimationLoop(tile, n);
627 SetAnimationFrame(tile, m);
628 MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
630 break;
632 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
633 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
634 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
635 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
636 if ((_tick_counter & 3) == 0) {
637 IndustryGfx gfx = GetIndustryGfx(tile);
639 gfx = (gfx < 155) ? gfx + 1 : 148;
640 SetIndustryGfx(tile, gfx);
641 MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
643 break;
645 case GFX_OILWELL_ANIMATED_1:
646 case GFX_OILWELL_ANIMATED_2:
647 case GFX_OILWELL_ANIMATED_3:
648 if ((_tick_counter & 7) == 0) {
649 bool b = Chance16(1, 7);
650 IndustryGfx gfx = GetIndustryGfx(tile);
652 byte m = GetAnimationFrame(tile) + 1;
653 if (m == 4 && (m = 0, ++gfx) == GFX_OILWELL_ANIMATED_3 + 1 && (gfx = GFX_OILWELL_ANIMATED_1, b)) {
654 SetIndustryGfx(tile, GFX_OILWELL_NOT_ANIMATED);
655 SetIndustryConstructionStage(tile, 3);
656 DeleteAnimatedTile(tile);
657 } else {
658 SetAnimationFrame(tile, m);
659 SetIndustryGfx(tile, gfx);
660 MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
663 break;
665 case GFX_COAL_MINE_TOWER_ANIMATED:
666 case GFX_COPPER_MINE_TOWER_ANIMATED:
667 case GFX_GOLD_MINE_TOWER_ANIMATED: {
668 int state = _tick_counter & 0x7FF;
670 if ((state -= 0x400) < 0) return;
672 if (state < 0x1A0) {
673 if (state < 0x20 || state >= 0x180) {
674 byte m = GetAnimationFrame(tile);
675 if (!(m & 0x40)) {
676 SetAnimationFrame(tile, m | 0x40);
677 if (_settings_client.sound.ambient) SndPlayTileFx(SND_0B_MINING_MACHINERY, tile);
679 if (state & 7) return;
680 } else {
681 if (state & 3) return;
683 byte m = (GetAnimationFrame(tile) + 1) | 0x40;
684 if (m > 0xC2) m = 0xC0;
685 SetAnimationFrame(tile, m);
686 MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
687 } else if (state >= 0x200 && state < 0x3A0) {
688 int i = (state < 0x220 || state >= 0x380) ? 7 : 3;
689 if (state & i) return;
691 byte m = (GetAnimationFrame(tile) & 0xBF) - 1;
692 if (m < 0x80) m = 0x82;
693 SetAnimationFrame(tile, m);
694 MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
696 break;
701 static void CreateChimneySmoke(TileIndex tile)
703 uint x = TileX(tile) * TILE_SIZE;
704 uint y = TileY(tile) * TILE_SIZE;
705 int z = GetTileMaxPixelZ(tile);
707 CreateEffectVehicle(x + 15, y + 14, z + 59, EV_CHIMNEY_SMOKE);
710 static void MakeIndustryTileBigger(TileIndex tile)
712 byte cnt = GetIndustryConstructionCounter(tile) + 1;
713 if (cnt != 4) {
714 SetIndustryConstructionCounter(tile, cnt);
715 return;
718 byte stage = GetIndustryConstructionStage(tile) + 1;
719 SetIndustryConstructionCounter(tile, 0);
720 SetIndustryConstructionStage(tile, stage);
721 StartStopIndustryTileAnimation(tile, IAT_CONSTRUCTION_STATE_CHANGE);
722 if (stage == INDUSTRY_COMPLETED) SetIndustryCompleted(tile);
724 MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
726 if (!IsIndustryCompleted(tile)) return;
728 IndustryGfx gfx = GetIndustryGfx(tile);
729 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
730 /* New industries are already animated on construction. */
731 return;
734 switch (gfx) {
735 case GFX_POWERPLANT_CHIMNEY:
736 CreateChimneySmoke(tile);
737 break;
739 case GFX_OILRIG_1: {
740 /* Do not require an industry tile to be after the first two GFX_OILRIG_1
741 * tiles (like the default oil rig). Do a proper check to ensure the
742 * tiles belong to the same industry and based on that build the oil rig's
743 * station. */
744 TileIndex other = tile + TileDiffXY(0, 1);
746 if (IsTileType(other, MP_INDUSTRY) &&
747 GetIndustryGfx(other) == GFX_OILRIG_1 &&
748 GetIndustryIndex(tile) == GetIndustryIndex(other)) {
749 BuildOilRig(tile);
751 break;
754 case GFX_TOY_FACTORY:
755 case GFX_BUBBLE_CATCHER:
756 case GFX_TOFFEE_QUARY:
757 SetAnimationFrame(tile, 0);
758 SetIndustryAnimationLoop(tile, 0);
759 break;
761 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
762 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
763 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
764 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
765 AddAnimatedTile(tile);
766 break;
770 static void TileLoopIndustry_BubbleGenerator(TileIndex tile)
772 static const int8 _bubble_spawn_location[3][4] = {
773 { 11, 0, -4, -14 },
774 { -4, -10, -4, 1 },
775 { 49, 59, 60, 65 },
778 if (_settings_client.sound.ambient) SndPlayTileFx(SND_2E_EXTRACT_AND_POP, tile);
780 int dir = Random() & 3;
782 EffectVehicle *v = CreateEffectVehicleAbove(
783 TileX(tile) * TILE_SIZE + _bubble_spawn_location[0][dir],
784 TileY(tile) * TILE_SIZE + _bubble_spawn_location[1][dir],
785 _bubble_spawn_location[2][dir],
786 EV_BUBBLE
789 if (v != NULL) v->animation_substate = dir;
792 static void TileLoop_Industry(TileIndex tile)
794 if (IsTileOnWater(tile)) TileLoop_Water(tile);
796 /* Normally this doesn't happen, but if an industry NewGRF is removed
797 * an industry that was previously build on water can now be flooded.
798 * If this happens the tile is no longer an industry tile after
799 * returning from TileLoop_Water. */
800 if (!IsTileType(tile, MP_INDUSTRY)) return;
802 TriggerIndustryTile(tile, INDTILE_TRIGGER_TILE_LOOP);
804 if (!IsIndustryCompleted(tile)) {
805 MakeIndustryTileBigger(tile);
806 return;
809 if (_game_mode == GM_EDITOR) return;
811 if (TransportIndustryGoods(tile) && !StartStopIndustryTileAnimation(Industry::GetByTile(tile), IAT_INDUSTRY_DISTRIBUTES_CARGO)) {
812 uint newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_production;
814 if (newgfx != INDUSTRYTILE_NOANIM) {
815 ResetIndustryConstructionStage(tile);
816 SetIndustryCompleted(tile);
817 SetIndustryGfx(tile, newgfx);
818 MarkTileDirtyByTile(tile);
819 return;
823 if (StartStopIndustryTileAnimation(tile, IAT_TILELOOP)) return;
825 IndustryGfx newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_next;
826 if (newgfx != INDUSTRYTILE_NOANIM) {
827 ResetIndustryConstructionStage(tile);
828 SetIndustryGfx(tile, newgfx);
829 MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
830 return;
833 IndustryGfx gfx = GetIndustryGfx(tile);
834 switch (gfx) {
835 case GFX_COAL_MINE_TOWER_NOT_ANIMATED:
836 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED:
837 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED:
838 if (!(_tick_counter & 0x400) && Chance16(1, 2)) {
839 switch (gfx) {
840 case GFX_COAL_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COAL_MINE_TOWER_ANIMATED; break;
841 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_ANIMATED; break;
842 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_ANIMATED; break;
844 SetIndustryGfx(tile, gfx);
845 SetAnimationFrame(tile, 0x80);
846 AddAnimatedTile(tile);
848 break;
850 case GFX_OILWELL_NOT_ANIMATED:
851 if (Chance16(1, 6)) {
852 SetIndustryGfx(tile, GFX_OILWELL_ANIMATED_1);
853 SetAnimationFrame(tile, 0);
854 AddAnimatedTile(tile);
856 break;
858 case GFX_COAL_MINE_TOWER_ANIMATED:
859 case GFX_COPPER_MINE_TOWER_ANIMATED:
860 case GFX_GOLD_MINE_TOWER_ANIMATED:
861 if (!(_tick_counter & 0x400)) {
862 switch (gfx) {
863 case GFX_COAL_MINE_TOWER_ANIMATED: gfx = GFX_COAL_MINE_TOWER_NOT_ANIMATED; break;
864 case GFX_COPPER_MINE_TOWER_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_NOT_ANIMATED; break;
865 case GFX_GOLD_MINE_TOWER_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_NOT_ANIMATED; break;
867 SetIndustryGfx(tile, gfx);
868 SetIndustryCompleted(tile);
869 SetIndustryConstructionStage(tile, 3);
870 DeleteAnimatedTile(tile);
872 break;
874 case GFX_POWERPLANT_SPARKS:
875 if (Chance16(1, 3)) {
876 if (_settings_client.sound.ambient) SndPlayTileFx(SND_0C_ELECTRIC_SPARK, tile);
877 AddAnimatedTile(tile);
879 break;
881 case GFX_COPPER_MINE_CHIMNEY:
882 CreateEffectVehicleAbove(TileX(tile) * TILE_SIZE + 6, TileY(tile) * TILE_SIZE + 6, 43, EV_COPPER_MINE_SMOKE);
883 break;
886 case GFX_TOY_FACTORY: {
887 Industry *i = Industry::GetByTile(tile);
888 if (i->was_cargo_delivered) {
889 i->was_cargo_delivered = false;
890 SetIndustryAnimationLoop(tile, 0);
891 AddAnimatedTile(tile);
894 break;
896 case GFX_BUBBLE_GENERATOR:
897 TileLoopIndustry_BubbleGenerator(tile);
898 break;
900 case GFX_TOFFEE_QUARY:
901 AddAnimatedTile(tile);
902 break;
904 case GFX_SUGAR_MINE_SIEVE:
905 if (Chance16(1, 3)) AddAnimatedTile(tile);
906 break;
910 static bool ClickTile_Industry(TileIndex tile)
912 ShowIndustryViewWindow(GetIndustryIndex(tile));
913 return true;
916 static TrackStatus GetTileTrackStatus_Industry(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
918 return 0;
921 static void ChangeTileOwner_Industry(TileIndex tile, Owner old_owner, Owner new_owner)
923 /* If the founder merges, the industry was created by the merged company */
924 Industry *i = Industry::GetByTile(tile);
925 if (i->founder == old_owner) i->founder = (new_owner == INVALID_OWNER) ? OWNER_NONE : new_owner;
929 * Check whether the tile is a forest.
930 * @param tile the tile to investigate.
931 * @return true if and only if the tile is a forest
933 bool IsTileForestIndustry(TileIndex tile)
935 /* Check for industry tile */
936 if (!IsTileType(tile, MP_INDUSTRY)) return false;
938 const Industry *ind = Industry::GetByTile(tile);
940 /* Check for organic industry (i.e. not processing or extractive) */
941 if ((GetIndustrySpec(ind->type)->life_type & INDUSTRYLIFE_ORGANIC) == 0) return false;
943 /* Check for wood production */
944 for (uint i = 0; i < lengthof(ind->produced_cargo); i++) {
945 /* The industry produces wood. */
946 if (ind->produced_cargo[i] != CT_INVALID && CargoSpec::Get(ind->produced_cargo[i])->label == 'WOOD') return true;
949 return false;
952 static const byte _plantfarmfield_type[] = {1, 1, 1, 1, 1, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6};
955 * Check whether the tile can be replaced by a farm field.
956 * @param tile the tile to investigate.
957 * @param allow_fields if true, the method will return true even if
958 * the tile is a farm tile, otherwise the tile may not be a farm tile
959 * @return true if the tile can become a farm field
961 static bool IsSuitableForFarmField(TileIndex tile, bool allow_fields)
963 switch (GetTileType(tile)) {
964 case MP_CLEAR: return !IsClearGround(tile, CLEAR_SNOW) && !IsClearGround(tile, CLEAR_DESERT) && (allow_fields || !IsClearGround(tile, CLEAR_FIELDS));
965 case MP_TREES: return GetTreeGround(tile) != TREE_GROUND_SHORE;
966 default: return false;
971 * Build farm field fence
972 * @param tile the tile to position the fence on
973 * @param size the size of the field being planted in tiles
974 * @param type type of fence to set
975 * @param side the side of the tile to attempt placement
977 static void SetupFarmFieldFence(TileIndex tile, int size, byte type, DiagDirection side)
979 TileIndexDiff diff = (DiagDirToAxis(side) == AXIS_Y ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
981 do {
982 tile = TILE_MASK(tile);
984 if (IsTileType(tile, MP_CLEAR) && IsClearGround(tile, CLEAR_FIELDS)) {
985 byte or_ = type;
987 if (or_ == 1 && Chance16(1, 7)) or_ = 2;
989 SetFence(tile, side, or_);
992 tile += diff;
993 } while (--size);
996 static void PlantFarmField(TileIndex tile, IndustryID industry)
998 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
999 if (GetTileZ(tile) + 2 >= GetSnowLine()) return;
1002 /* determine field size */
1003 uint32 r = (Random() & 0x303) + 0x404;
1004 if (_settings_game.game_creation.landscape == LT_ARCTIC) r += 0x404;
1005 uint size_x = GB(r, 0, 8);
1006 uint size_y = GB(r, 8, 8);
1008 TileArea ta(tile - TileDiffXY(min(TileX(tile), size_x / 2), min(TileY(tile), size_y / 2)), size_x, size_y);
1009 ta.ClampToMap();
1011 if (ta.w == 0 || ta.h == 0) return;
1013 /* check the amount of bad tiles */
1014 int count = 0;
1015 TILE_AREA_LOOP(cur_tile, ta) {
1016 assert(cur_tile < MapSize());
1017 count += IsSuitableForFarmField(cur_tile, false);
1019 if (count * 2 < ta.w * ta.h) return;
1021 /* determine type of field */
1022 r = Random();
1023 uint counter = GB(r, 5, 3);
1024 uint field_type = GB(r, 8, 8) * 9 >> 8;
1026 /* make field */
1027 TILE_AREA_LOOP(cur_tile, ta) {
1028 assert(cur_tile < MapSize());
1029 if (IsSuitableForFarmField(cur_tile, true)) {
1030 MakeField(cur_tile, field_type, industry);
1031 SetClearCounter(cur_tile, counter);
1032 MarkTileDirtyByTile(cur_tile, ZOOM_LVL_DRAW_MAP);
1036 int type = 3;
1037 if (_settings_game.game_creation.landscape != LT_ARCTIC && _settings_game.game_creation.landscape != LT_TROPIC) {
1038 type = _plantfarmfield_type[Random() & 0xF];
1041 SetupFarmFieldFence(ta.tile, ta.h, type, DIAGDIR_NE);
1042 SetupFarmFieldFence(ta.tile, ta.w, type, DIAGDIR_NW);
1043 SetupFarmFieldFence(ta.tile + TileDiffXY(ta.w - 1, 0), ta.h, type, DIAGDIR_SW);
1044 SetupFarmFieldFence(ta.tile + TileDiffXY(0, ta.h - 1), ta.w, type, DIAGDIR_SE);
1047 void PlantRandomFarmField(const Industry *i)
1049 int x = i->location.w / 2 + Random() % 31 - 16;
1050 int y = i->location.h / 2 + Random() % 31 - 16;
1052 TileIndex tile = TileAddWrap(i->location.tile, x, y);
1054 if (tile != INVALID_TILE) PlantFarmField(tile, i->index);
1058 * Search callback function for ChopLumberMillTrees
1059 * @param tile to test
1060 * @param user_data that is passed by the caller. In this case, nothing
1061 * @return the result of the test
1063 static bool SearchLumberMillTrees(TileIndex tile, void *user_data)
1065 if (IsTileType(tile, MP_TREES) && GetTreeGrowth(tile) > 2) { ///< 3 and up means all fully grown trees
1066 /* found a tree */
1068 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
1070 _industry_sound_ctr = 1;
1071 _industry_sound_tile = tile;
1072 if (_settings_client.sound.ambient) SndPlayTileFx(SND_38_CHAINSAW, tile);
1074 DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
1076 cur_company.Restore();
1077 return true;
1079 return false;
1083 * Perform a circular search around the Lumber Mill in order to find trees to cut
1084 * @param i industry
1086 static void ChopLumberMillTrees(Industry *i)
1088 /* We only want to cut trees if all tiles are completed. */
1089 TILE_AREA_LOOP(tile_cur, i->location) {
1090 if (i->TileBelongsToIndustry(tile_cur)) {
1091 if (!IsIndustryCompleted(tile_cur)) return;
1095 TileIndex tile = i->location.tile;
1096 if (CircularTileSearch(&tile, 40, SearchLumberMillTrees, NULL)) { // 40x40 tiles to search.
1097 i->produced_cargo_waiting[0] = min(0xffff, i->produced_cargo_waiting[0] + 45); // Found a tree, add according value to waiting cargo.
1101 static void ProduceIndustryGoods(Industry *i)
1103 const IndustrySpec *indsp = GetIndustrySpec(i->type);
1105 /* play a sound? */
1106 if ((i->counter & 0x3F) == 0) {
1107 uint32 r;
1108 uint num;
1109 if (Chance16R(1, 14, r) && (num = indsp->number_of_sounds) != 0 && _settings_client.sound.ambient) {
1110 SndPlayTileFx(
1111 (SoundFx)(indsp->random_sounds[((r >> 16) * num) >> 16]),
1112 i->location.tile);
1116 i->counter--;
1118 /* produce some cargo */
1119 if ((i->counter % INDUSTRY_PRODUCE_TICKS) == 0) {
1120 if (HasBit(indsp->callback_mask, CBM_IND_PRODUCTION_256_TICKS)) IndustryProductionCallback(i, 1);
1122 IndustryBehaviour indbehav = indsp->behaviour;
1123 i->produced_cargo_waiting[0] = min(0xffff, i->produced_cargo_waiting[0] + i->production_rate[0]);
1124 i->produced_cargo_waiting[1] = min(0xffff, i->produced_cargo_waiting[1] + i->production_rate[1]);
1126 if ((indbehav & INDUSTRYBEH_PLANT_FIELDS) != 0) {
1127 uint16 cb_res = CALLBACK_FAILED;
1128 if (HasBit(indsp->callback_mask, CBM_IND_SPECIAL_EFFECT)) {
1129 cb_res = GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 0, i, i->type, i->location.tile);
1132 bool plant;
1133 if (cb_res != CALLBACK_FAILED) {
1134 plant = ConvertBooleanCallback(indsp->grf_prop.grffile, CBID_INDUSTRY_SPECIAL_EFFECT, cb_res);
1135 } else {
1136 plant = Chance16(1, 8);
1139 if (plant) PlantRandomFarmField(i);
1141 if ((indbehav & INDUSTRYBEH_CUT_TREES) != 0) {
1142 uint16 cb_res = CALLBACK_FAILED;
1143 if (HasBit(indsp->callback_mask, CBM_IND_SPECIAL_EFFECT)) {
1144 cb_res = GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 1, i, i->type, i->location.tile);
1147 bool cut;
1148 if (cb_res != CALLBACK_FAILED) {
1149 cut = ConvertBooleanCallback(indsp->grf_prop.grffile, CBID_INDUSTRY_SPECIAL_EFFECT, cb_res);
1150 } else {
1151 cut = ((i->counter % INDUSTRY_CUT_TREE_TICKS) == 0);
1154 if (cut) ChopLumberMillTrees(i);
1157 TriggerIndustry(i, INDUSTRY_TRIGGER_INDUSTRY_TICK);
1158 StartStopIndustryTileAnimation(i, IAT_INDUSTRY_TICK);
1162 void OnTick_Industry()
1164 if (_industry_sound_ctr != 0) {
1165 _industry_sound_ctr++;
1167 if (_industry_sound_ctr == 75) {
1168 if (_settings_client.sound.ambient) SndPlayTileFx(SND_37_BALLOON_SQUEAK, _industry_sound_tile);
1169 } else if (_industry_sound_ctr == 160) {
1170 _industry_sound_ctr = 0;
1171 if (_settings_client.sound.ambient) SndPlayTileFx(SND_36_CARTOON_CRASH, _industry_sound_tile);
1175 if (_game_mode == GM_EDITOR) return;
1177 Industry *i;
1178 FOR_ALL_INDUSTRIES(i) {
1179 ProduceIndustryGoods(i);
1184 * Check the conditions of #CHECK_NOTHING (Always succeeds).
1185 * @param tile %Tile to perform the checking.
1186 * @return Succeeded or failed command.
1188 static CommandCost CheckNewIndustry_NULL(TileIndex tile)
1190 return CommandCost();
1194 * Check the conditions of #CHECK_FOREST (Industry should be build above snow-line in arctic climate).
1195 * @param tile %Tile to perform the checking.
1196 * @return Succeeded or failed command.
1198 static CommandCost CheckNewIndustry_Forest(TileIndex tile)
1200 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
1201 if (GetTileZ(tile) < HighestSnowLine() + 2) {
1202 return_cmd_error(STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED);
1205 return CommandCost();
1209 * Check the conditions of #CHECK_REFINERY (Industry should be positioned near edge of the map).
1210 * @param tile %Tile to perform the checking.
1211 * @return Succeeded or failed command.
1213 static CommandCost CheckNewIndustry_OilRefinery(TileIndex tile)
1215 if (_game_mode == GM_EDITOR) return CommandCost();
1216 if (DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _settings_game.game_creation.oil_refinery_limit) return CommandCost();
1218 return_cmd_error(STR_ERROR_CAN_ONLY_BE_POSITIONED);
1221 extern bool _ignore_restrictions;
1224 * Check the conditions of #CHECK_OIL_RIG (Industries at sea should be positioned near edge of the map).
1225 * @param tile %Tile to perform the checking.
1226 * @return Succeeded or failed command.
1228 static CommandCost CheckNewIndustry_OilRig(TileIndex tile)
1230 if (_game_mode == GM_EDITOR && _ignore_restrictions) return CommandCost();
1231 if (TileHeight(tile) == 0 &&
1232 DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _settings_game.game_creation.oil_refinery_limit) return CommandCost();
1234 return_cmd_error(STR_ERROR_CAN_ONLY_BE_POSITIONED);
1238 * Check the conditions of #CHECK_FARM (Industry should be below snow-line in arctic).
1239 * @param tile %Tile to perform the checking.
1240 * @return Succeeded or failed command.
1242 static CommandCost CheckNewIndustry_Farm(TileIndex tile)
1244 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
1245 if (GetTileZ(tile) + 2 >= HighestSnowLine()) {
1246 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1249 return CommandCost();
1253 * Check the conditions of #CHECK_PLANTATION (Industry should NOT be in the desert).
1254 * @param tile %Tile to perform the checking.
1255 * @return Succeeded or failed command.
1257 static CommandCost CheckNewIndustry_Plantation(TileIndex tile)
1259 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
1260 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1262 return CommandCost();
1266 * Check the conditions of #CHECK_WATER (Industry should be in the desert).
1267 * @param tile %Tile to perform the checking.
1268 * @return Succeeded or failed command.
1270 static CommandCost CheckNewIndustry_Water(TileIndex tile)
1272 if (GetTropicZone(tile) != TROPICZONE_DESERT) {
1273 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT);
1275 return CommandCost();
1279 * Check the conditions of #CHECK_LUMBERMILL (Industry should be in the rain forest).
1280 * @param tile %Tile to perform the checking.
1281 * @return Succeeded or failed command.
1283 static CommandCost CheckNewIndustry_Lumbermill(TileIndex tile)
1285 if (GetTropicZone(tile) != TROPICZONE_RAINFOREST) {
1286 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST);
1288 return CommandCost();
1292 * Check the conditions of #CHECK_BUBBLEGEN (Industry should be in low land).
1293 * @param tile %Tile to perform the checking.
1294 * @return Succeeded or failed command.
1296 static CommandCost CheckNewIndustry_BubbleGen(TileIndex tile)
1298 if (GetTileZ(tile) > 4) {
1299 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS);
1301 return CommandCost();
1305 * Industrytype check function signature.
1306 * @param tile %Tile to check.
1307 * @return Succeeded or failed command.
1309 typedef CommandCost CheckNewIndustryProc(TileIndex tile);
1311 /** Check functions for different types of industry. */
1312 static CheckNewIndustryProc * const _check_new_industry_procs[CHECK_END] = {
1313 CheckNewIndustry_NULL, ///< CHECK_NOTHING
1314 CheckNewIndustry_Forest, ///< CHECK_FOREST
1315 CheckNewIndustry_OilRefinery, ///< CHECK_REFINERY
1316 CheckNewIndustry_Farm, ///< CHECK_FARM
1317 CheckNewIndustry_Plantation, ///< CHECK_PLANTATION
1318 CheckNewIndustry_Water, ///< CHECK_WATER
1319 CheckNewIndustry_Lumbermill, ///< CHECK_LUMBERMILL
1320 CheckNewIndustry_BubbleGen, ///< CHECK_BUBBLEGEN
1321 CheckNewIndustry_OilRig, ///< CHECK_OIL_RIG
1325 * Find a town for the industry, while checking for multiple industries in the same town.
1326 * @param tile Position of the industry to build.
1327 * @param type Industry type.
1328 * @param [out] town Pointer to return town for the new industry, \c NULL is written if no good town can be found.
1329 * @return Succeeded or failed command.
1331 * @pre \c *t != NULL
1332 * @post \c *t points to a town on success, and \c NULL on failure.
1334 static CommandCost FindTownForIndustry(TileIndex tile, int type, Town **t)
1336 *t = ClosestTownFromTile(tile, UINT_MAX);
1338 if (_settings_game.economy.multiple_industry_per_town) return CommandCost();
1340 const Industry *i;
1341 FOR_ALL_INDUSTRIES(i) {
1342 if (i->type == (byte)type && i->town == *t) {
1343 *t = NULL;
1344 return_cmd_error(STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN);
1348 return CommandCost();
1351 bool IsSlopeRefused(Slope current, Slope refused)
1353 if (IsSteepSlope(current)) return true;
1354 if (current != SLOPE_FLAT) {
1355 if (IsSteepSlope(refused)) return true;
1357 Slope t = ComplementSlope(current);
1359 if ((refused & SLOPE_W) && (t & SLOPE_NW)) return true;
1360 if ((refused & SLOPE_S) && (t & SLOPE_NE)) return true;
1361 if ((refused & SLOPE_E) && (t & SLOPE_SW)) return true;
1362 if ((refused & SLOPE_N) && (t & SLOPE_SE)) return true;
1365 return false;
1369 * Are the tiles of the industry free?
1370 * @param tile Position to check.
1371 * @param it Industry tiles table.
1372 * @param itspec_index The index of the itsepc to build/fund
1373 * @param type Type of the industry.
1374 * @param initial_random_bits The random bits the industry is going to have after construction.
1375 * @param founder Industry founder
1376 * @param creation_type The circumstances the industry is created under.
1377 * @param [out] custom_shape_check Perform custom check for the site.
1378 * @return Failed or succeeded command.
1380 static CommandCost CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTileTable *it, uint itspec_index, int type, uint16 initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type, bool *custom_shape_check = NULL)
1382 bool refused_slope = false;
1383 bool custom_shape = false;
1385 do {
1386 IndustryGfx gfx = GetTranslatedIndustryTileID(it->gfx);
1387 TileIndex cur_tile = TileAddWrap(tile, it->ti.x, it->ti.y);
1389 if (!IsValidTile(cur_tile)) {
1390 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1393 if (gfx == GFX_WATERTILE_SPECIALCHECK) {
1394 if (!IsWaterTile(cur_tile) ||
1395 !IsTileFlat(cur_tile)) {
1396 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1398 } else {
1399 CommandCost ret = EnsureNoVehicleOnGround(cur_tile);
1400 if (ret.Failed()) return ret;
1401 if (IsBridgeAbove(cur_tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1403 const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
1405 IndustryBehaviour ind_behav = GetIndustrySpec(type)->behaviour;
1407 /* Perform land/water check if not disabled */
1408 if (!HasBit(its->slopes_refused, 5) && ((HasTileWaterClass(cur_tile) && IsTileOnWater(cur_tile)) == !(ind_behav & INDUSTRYBEH_BUILT_ONWATER))) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1410 if (HasBit(its->callback_mask, CBM_INDT_SHAPE_CHECK)) {
1411 custom_shape = true;
1412 CommandCost ret = PerformIndustryTileSlopeCheck(tile, cur_tile, its, type, gfx, itspec_index, initial_random_bits, founder, creation_type);
1413 if (ret.Failed()) return ret;
1414 } else {
1415 Slope tileh = GetTileSlope(cur_tile);
1416 refused_slope |= IsSlopeRefused(tileh, its->slopes_refused);
1419 if ((ind_behav & (INDUSTRYBEH_ONLY_INTOWN | INDUSTRYBEH_TOWN1200_MORE)) || // Tile must be a house
1420 ((ind_behav & INDUSTRYBEH_ONLY_NEARTOWN) && IsTileType(cur_tile, MP_HOUSE))) { // Tile is allowed to be a house (and it is a house)
1421 if (!IsTileType(cur_tile, MP_HOUSE)) {
1422 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS);
1425 /* Clear the tiles as OWNER_TOWN to not affect town rating, and to not clear protected buildings */
1426 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
1427 CommandCost ret = DoCommand(cur_tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR);
1428 cur_company.Restore();
1430 if (ret.Failed()) return ret;
1431 } else {
1432 /* Clear the tiles, but do not affect town ratings */
1433 CommandCost ret = DoCommand(cur_tile, 0, 0, DC_AUTO | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR);
1435 if (ret.Failed()) return ret;
1438 } while ((++it)->ti.x != -0x80);
1440 if (custom_shape_check != NULL) *custom_shape_check = custom_shape;
1442 /* It is almost impossible to have a fully flat land in TG, so what we
1443 * do is that we check if we can make the land flat later on. See
1444 * CheckIfCanLevelIndustryPlatform(). */
1445 if (!refused_slope || (_settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world && !custom_shape && !_ignore_restrictions)) {
1446 return CommandCost();
1448 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1452 * Is the industry allowed to be built at this place for the town?
1453 * @param tile Tile to construct the industry.
1454 * @param type Type of the industry.
1455 * @param t Town authority that the industry belongs to.
1456 * @return Succeeded or failed command.
1458 static CommandCost CheckIfIndustryIsAllowed(TileIndex tile, int type, const Town *t)
1460 if ((GetIndustrySpec(type)->behaviour & INDUSTRYBEH_TOWN1200_MORE) && t->cache.population < 1200) {
1461 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200);
1464 if ((GetIndustrySpec(type)->behaviour & INDUSTRYBEH_ONLY_NEARTOWN) && DistanceMax(t->xy, tile) > 9) {
1465 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER);
1468 return CommandCost();
1471 static bool CheckCanTerraformSurroundingTiles(TileIndex tile, uint height, int internal)
1473 /* Check if we don't leave the map */
1474 if (TileX(tile) == 0 || TileY(tile) == 0 || GetTileType(tile) == MP_VOID) return false;
1476 TileArea ta(tile - TileDiffXY(1, 1), 2, 2);
1477 TILE_AREA_LOOP(tile_walk, ta) {
1478 uint curh = TileHeight(tile_walk);
1479 /* Is the tile clear? */
1480 if ((GetTileType(tile_walk) != MP_CLEAR) && (GetTileType(tile_walk) != MP_TREES)) return false;
1482 /* Don't allow too big of a change if this is the sub-tile check */
1483 if (internal != 0 && Delta(curh, height) > 1) return false;
1485 /* Different height, so the surrounding tiles of this tile
1486 * has to be correct too (in level, or almost in level)
1487 * else you get a chain-reaction of terraforming. */
1488 if (internal == 0 && curh != height) {
1489 if (TileX(tile_walk) == 0 || TileY(tile_walk) == 0 || !CheckCanTerraformSurroundingTiles(tile_walk + TileDiffXY(-1, -1), height, internal + 1)) {
1490 return false;
1495 return true;
1499 * This function tries to flatten out the land below an industry, without
1500 * damaging the surroundings too much.
1502 static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, DoCommandFlag flags, const IndustryTileTable *it, int type)
1504 const int MKEND = -0x80; // used for last element in an IndustryTileTable (see build_industry.h)
1505 int max_x = 0;
1506 int max_y = 0;
1508 /* Finds dimensions of largest variant of this industry */
1509 do {
1510 if (it->gfx == 0xFF) continue; // FF been a marquer for a check on clear water, skip it
1511 if (it->ti.x > max_x) max_x = it->ti.x;
1512 if (it->ti.y > max_y) max_y = it->ti.y;
1513 } while ((++it)->ti.x != MKEND);
1515 /* Remember level height */
1516 uint h = TileHeight(tile);
1518 if (TileX(tile) <= _settings_game.construction.industry_platform + 1U || TileY(tile) <= _settings_game.construction.industry_platform + 1U) return false;
1519 /* Check that all tiles in area and surrounding are clear
1520 * this determines that there are no obstructing items */
1522 TileArea ta(tile + TileDiffXY(-_settings_game.construction.industry_platform, -_settings_game.construction.industry_platform),
1523 max_x + 2 + 2 * _settings_game.construction.industry_platform, max_y + 2 + 2 * _settings_game.construction.industry_platform);
1525 if (TileX(ta.tile) + ta.w >= MapMaxX() || TileY(ta.tile) + ta.h >= MapMaxY()) return false;
1527 /* _current_company is OWNER_NONE for randomly generated industries and in editor, or the company who funded or prospected the industry.
1528 * Perform terraforming as OWNER_TOWN to disable autoslope and town ratings. */
1529 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
1531 TILE_AREA_LOOP(tile_walk, ta) {
1532 uint curh = TileHeight(tile_walk);
1533 if (curh != h) {
1534 /* This tile needs terraforming. Check if we can do that without
1535 * damaging the surroundings too much. */
1536 if (!CheckCanTerraformSurroundingTiles(tile_walk, h, 0)) {
1537 cur_company.Restore();
1538 return false;
1540 /* This is not 100% correct check, but the best we can do without modifying the map.
1541 * What is missing, is if the difference in height is more than 1.. */
1542 if (DoCommand(tile_walk, SLOPE_N, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND).Failed()) {
1543 cur_company.Restore();
1544 return false;
1549 if (flags & DC_EXEC) {
1550 /* Terraform the land under the industry */
1551 TILE_AREA_LOOP(tile_walk, ta) {
1552 uint curh = TileHeight(tile_walk);
1553 while (curh != h) {
1554 /* We give the terraforming for free here, because we can't calculate
1555 * exact cost in the test-round, and as we all know, that will cause
1556 * a nice assert if they don't match ;) */
1557 DoCommand(tile_walk, SLOPE_N, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND);
1558 curh += (curh > h) ? -1 : 1;
1563 cur_company.Restore();
1564 return true;
1569 * Check that the new industry is far enough from conflicting industries.
1570 * @param tile Tile to construct the industry.
1571 * @param type Type of the new industry.
1572 * @return Succeeded or failed command.
1574 static CommandCost CheckIfFarEnoughFromConflictingIndustry(TileIndex tile, int type)
1576 const IndustrySpec *indspec = GetIndustrySpec(type);
1577 const Industry *i = NULL;
1579 /* On a large map with many industries, it may be faster to check an area. */
1580 static const int dmax = 14;
1581 if (Industry::GetNumItems() > (size_t) (dmax * dmax * 2)) {
1582 const int tx = TileX(tile);
1583 const int ty = TileY(tile);
1584 TileArea tile_area = TileArea(TileXY(max(0, tx - dmax), max(0, ty - dmax)), TileXY(min(MapMaxX(), tx + dmax), min(MapMaxY(), ty + dmax)));
1585 TILE_AREA_LOOP(atile, tile_area) {
1586 if (GetTileType(atile) == MP_INDUSTRY) {
1587 const Industry *i2 = Industry::GetByTile(atile);
1588 if (i == i2) continue;
1589 i = i2;
1590 if (DistanceMax(tile, i->location.tile) > (uint)dmax) continue;
1591 if (i->type == indspec->conflicting[0] ||
1592 i->type == indspec->conflicting[1] ||
1593 i->type == indspec->conflicting[2]) {
1594 return_cmd_error(STR_ERROR_INDUSTRY_TOO_CLOSE);
1598 return CommandCost();
1601 FOR_ALL_INDUSTRIES(i) {
1602 /* Within 14 tiles from another industry is considered close */
1603 if (DistanceMax(tile, i->location.tile) > 14) continue;
1605 /* check if there are any conflicting industry types around */
1606 if (i->type == indspec->conflicting[0] ||
1607 i->type == indspec->conflicting[1] ||
1608 i->type == indspec->conflicting[2]) {
1609 return_cmd_error(STR_ERROR_INDUSTRY_TOO_CLOSE);
1612 return CommandCost();
1616 * Advertise about a new industry opening.
1617 * @param ind Industry being opened.
1619 static void AdvertiseIndustryOpening(const Industry *ind)
1621 const IndustrySpec *ind_spc = GetIndustrySpec(ind->type);
1622 SetDParam(0, ind_spc->name);
1623 if (ind_spc->new_industry_text > STR_LAST_STRINGID) {
1624 SetDParam(1, STR_TOWN_NAME);
1625 SetDParam(2, ind->town->index);
1626 } else {
1627 SetDParam(1, ind->town->index);
1629 AddIndustryNewsItem(ind_spc->new_industry_text, NT_INDUSTRY_OPEN, ind->index);
1630 AI::BroadcastNewEvent(new ScriptEventIndustryOpen(ind->index));
1631 Game::NewEvent(new ScriptEventIndustryOpen(ind->index));
1635 * Put an industry on the map.
1636 * @param i Just allocated poolitem, mostly empty.
1637 * @param tile North tile of the industry.
1638 * @param type Type of the industry.
1639 * @param it Industrylayout to build.
1640 * @param layout Number of the layout.
1641 * @param t Nearest town.
1642 * @param founder Founder of the industry; OWNER_NONE in case of random construction.
1643 * @param initial_random_bits Random bits for the industry.
1645 static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, const IndustryTileTable *it, byte layout, Town *t, Owner founder, uint16 initial_random_bits)
1647 const IndustrySpec *indspec = GetIndustrySpec(type);
1649 i->location = TileArea(tile, 1, 1);
1650 i->type = type;
1651 Industry::IncIndustryTypeCount(type);
1653 i->produced_cargo[0] = indspec->produced_cargo[0];
1654 i->produced_cargo[1] = indspec->produced_cargo[1];
1655 i->accepts_cargo[0] = indspec->accepts_cargo[0];
1656 i->accepts_cargo[1] = indspec->accepts_cargo[1];
1657 i->accepts_cargo[2] = indspec->accepts_cargo[2];
1658 i->production_rate[0] = indspec->production_rate[0];
1659 i->production_rate[1] = indspec->production_rate[1];
1661 /* don't use smooth economy for industries using production related callbacks */
1662 if (indspec->UsesSmoothEconomy()) {
1663 i->production_rate[0] = min((RandomRange(256) + 128) * i->production_rate[0] >> 8, 255);
1664 i->production_rate[1] = min((RandomRange(256) + 128) * i->production_rate[1] >> 8, 255);
1667 i->town = t;
1668 i->owner = OWNER_NONE;
1670 uint16 r = Random();
1671 i->random_colour = GB(r, 0, 4);
1672 i->counter = GB(r, 4, 12);
1673 i->random = initial_random_bits;
1674 i->produced_cargo_waiting[0] = 0;
1675 i->produced_cargo_waiting[1] = 0;
1676 i->incoming_cargo_waiting[0] = 0;
1677 i->incoming_cargo_waiting[1] = 0;
1678 i->incoming_cargo_waiting[2] = 0;
1679 i->this_month_production[0] = 0;
1680 i->this_month_production[1] = 0;
1681 i->this_month_transported[0] = 0;
1682 i->this_month_transported[1] = 0;
1683 i->last_month_pct_transported[0] = 0;
1684 i->last_month_pct_transported[1] = 0;
1685 i->last_month_transported[0] = 0;
1686 i->last_month_transported[1] = 0;
1687 i->was_cargo_delivered = false;
1688 i->last_prod_year = _cur_year;
1689 i->founder = founder;
1691 i->construction_date = _date;
1692 i->construction_type = (_game_mode == GM_EDITOR) ? ICT_SCENARIO_EDITOR :
1693 (_generating_world ? ICT_MAP_GENERATION : ICT_NORMAL_GAMEPLAY);
1695 /* Adding 1 here makes it conform to specs of var44 of varaction2 for industries
1696 * 0 = created prior of newindustries
1697 * else, chosen layout + 1 */
1698 i->selected_layout = layout + 1;
1700 i->prod_level = PRODLEVEL_DEFAULT;
1702 /* Call callbacks after the regular fields got initialised. */
1704 if (HasBit(indspec->callback_mask, CBM_IND_PROD_CHANGE_BUILD)) {
1705 uint16 res = GetIndustryCallback(CBID_INDUSTRY_PROD_CHANGE_BUILD, 0, Random(), i, type, INVALID_TILE);
1706 if (res != CALLBACK_FAILED) {
1707 if (res < PRODLEVEL_MINIMUM || res > PRODLEVEL_MAXIMUM) {
1708 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_PROD_CHANGE_BUILD, res);
1709 } else {
1710 i->prod_level = res;
1711 i->RecomputeProductionMultipliers();
1716 if (_generating_world) {
1717 i->last_month_production[0] = i->production_rate[0] * 8;
1718 i->last_month_production[1] = i->production_rate[1] * 8;
1719 } else {
1720 i->last_month_production[0] = i->last_month_production[1] = 0;
1723 if (HasBit(indspec->callback_mask, CBM_IND_DECIDE_COLOUR)) {
1724 uint16 res = GetIndustryCallback(CBID_INDUSTRY_DECIDE_COLOUR, 0, 0, i, type, INVALID_TILE);
1725 if (res != CALLBACK_FAILED) {
1726 if (GB(res, 4, 11) != 0) ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_DECIDE_COLOUR, res);
1727 i->random_colour = GB(res, 0, 4);
1731 if (HasBit(indspec->callback_mask, CBM_IND_INPUT_CARGO_TYPES)) {
1732 for (uint j = 0; j < lengthof(i->accepts_cargo); j++) i->accepts_cargo[j] = CT_INVALID;
1733 for (uint j = 0; j < lengthof(i->accepts_cargo); j++) {
1734 uint16 res = GetIndustryCallback(CBID_INDUSTRY_INPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE);
1735 if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
1736 if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
1737 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_INPUT_CARGO_TYPES, res);
1738 break;
1740 i->accepts_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
1744 if (HasBit(indspec->callback_mask, CBM_IND_OUTPUT_CARGO_TYPES)) {
1745 for (uint j = 0; j < lengthof(i->produced_cargo); j++) i->produced_cargo[j] = CT_INVALID;
1746 for (uint j = 0; j < lengthof(i->produced_cargo); j++) {
1747 uint16 res = GetIndustryCallback(CBID_INDUSTRY_OUTPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE);
1748 if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
1749 if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
1750 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_OUTPUT_CARGO_TYPES, res);
1751 break;
1753 i->produced_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
1757 /* Plant the tiles */
1759 do {
1760 TileIndex cur_tile = tile + ToTileIndexDiff(it->ti);
1762 if (it->gfx != GFX_WATERTILE_SPECIALCHECK) {
1763 i->location.Add(cur_tile);
1765 WaterClass wc = (IsWaterTile(cur_tile) ? GetWaterClass(cur_tile) : WATER_CLASS_INVALID);
1767 DoCommand(cur_tile, 0, 0, DC_EXEC | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR);
1769 MakeIndustry(cur_tile, i->index, it->gfx, Random(), wc);
1771 if (_generating_world) {
1772 SetIndustryConstructionCounter(cur_tile, 3);
1773 SetIndustryConstructionStage(cur_tile, 2);
1776 /* it->gfx is stored in the map. But the translated ID cur_gfx is the interesting one */
1777 IndustryGfx cur_gfx = GetTranslatedIndustryTileID(it->gfx);
1778 const IndustryTileSpec *its = GetIndustryTileSpec(cur_gfx);
1779 if (its->animation.status != ANIM_STATUS_NO_ANIMATION) AddAnimatedTile(cur_tile);
1781 } while ((++it)->ti.x != -0x80);
1783 if (GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_PLANT_ON_BUILT) {
1784 for (uint j = 0; j != 50; j++) PlantRandomFarmField(i);
1786 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0);
1788 Station::RecomputeIndustriesNearForAll();
1792 * Helper function for Build/Fund an industry
1793 * @param tile tile where industry is built
1794 * @param type of industry to build
1795 * @param flags of operations to conduct
1796 * @param indspec pointer to industry specifications
1797 * @param itspec_index the index of the itsepc to build/fund
1798 * @param seed random seed (possibly) used by industries
1799 * @param initial_random_bits The random bits the industry is going to have after construction.
1800 * @param founder Founder of the industry
1801 * @param creation_type The circumstances the industry is created under.
1802 * @param [out] ip Pointer to store newly created industry.
1803 * @return Succeeded or failed command.
1805 * @post \c *ip contains the newly created industry if all checks are successful and the \a flags request actual creation, else it contains \c NULL afterwards.
1807 static CommandCost CreateNewIndustryHelper(TileIndex tile, IndustryType type, DoCommandFlag flags, const IndustrySpec *indspec, uint itspec_index, uint32 random_var8f, uint16 random_initial_bits, Owner founder, IndustryAvailabilityCallType creation_type, Industry **ip)
1809 assert(itspec_index < indspec->num_table);
1810 const IndustryTileTable *it = indspec->table[itspec_index];
1811 bool custom_shape_check = false;
1813 *ip = NULL;
1815 SmallVector<ClearedObjectArea, 1> object_areas(_cleared_object_areas);
1816 CommandCost ret = CheckIfIndustryTilesAreFree(tile, it, itspec_index, type, random_initial_bits, founder, creation_type, &custom_shape_check);
1817 _cleared_object_areas = object_areas;
1818 if (ret.Failed()) return ret;
1820 if (HasBit(GetIndustrySpec(type)->callback_mask, CBM_IND_LOCATION)) {
1821 ret = CheckIfCallBackAllowsCreation(tile, type, itspec_index, random_var8f, random_initial_bits, founder, creation_type);
1822 } else {
1823 ret = _check_new_industry_procs[indspec->check_proc](tile);
1825 if (ret.Failed()) return ret;
1827 if (!custom_shape_check && _settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world &&
1828 !_ignore_restrictions && !CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER, it, type)) {
1829 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1832 ret = CheckIfFarEnoughFromConflictingIndustry(tile, type);
1833 if (ret.Failed()) return ret;
1835 Town *t = NULL;
1836 ret = FindTownForIndustry(tile, type, &t);
1837 if (ret.Failed()) return ret;
1838 assert(t != NULL);
1840 ret = CheckIfIndustryIsAllowed(tile, type, t);
1841 if (ret.Failed()) return ret;
1843 if (!Industry::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_INDUSTRIES);
1845 if (flags & DC_EXEC) {
1846 *ip = new Industry(tile);
1847 if (!custom_shape_check) CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER | DC_EXEC, it, type);
1848 DoCreateNewIndustry(*ip, tile, type, it, itspec_index, t, founder, random_initial_bits);
1851 return CommandCost();
1855 * Build/Fund an industry
1856 * @param tile tile where industry is built
1857 * @param flags of operations to conduct
1858 * @param p1 various bitstuffed elements
1859 * - p1 = (bit 0 - 7) - industry type see build_industry.h and see industry.h
1860 * - p1 = (bit 8 - 15) - first layout to try
1861 * - p1 = (bit 16 ) - 0 = prospect, 1 = fund (only valid if current company is DEITY)
1862 * @param p2 seed to use for desyncfree randomisations
1863 * @param text unused
1864 * @return the cost of this operation or an error
1866 CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1868 IndustryType it = GB(p1, 0, 8);
1869 if (it >= NUM_INDUSTRYTYPES) return CMD_ERROR;
1871 const IndustrySpec *indspec = GetIndustrySpec(it);
1873 /* Check if the to-be built/founded industry is available for this climate. */
1874 if (!indspec->enabled || indspec->num_table == 0) return CMD_ERROR;
1876 /* If the setting for raw-material industries is not on, you cannot build raw-material industries.
1877 * Raw material industries are industries that do not accept cargo (at least for now) */
1878 if (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 0 && indspec->IsRawIndustry()) {
1879 return CMD_ERROR;
1882 if (_game_mode != GM_EDITOR && GetIndustryProbabilityCallback(it, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, 1) == 0) {
1883 return CMD_ERROR;
1886 Randomizer randomizer;
1887 randomizer.SetSeed(p2);
1888 uint16 random_initial_bits = GB(p2, 0, 16);
1889 uint32 random_var8f = randomizer.Next();
1890 int num_layouts = indspec->num_table;
1891 CommandCost ret = CommandCost(STR_ERROR_SITE_UNSUITABLE);
1892 const bool deity_prospect = _current_company == OWNER_DEITY && !HasBit(p1, 16);
1894 Industry *ind = NULL;
1895 if (deity_prospect || (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 2 && indspec->IsRawIndustry())) {
1896 if (flags & DC_EXEC) {
1897 /* Prospected industries are build as OWNER_TOWN to not e.g. be build on owned land of the founder */
1898 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
1899 /* Prospecting has a chance to fail, however we cannot guarantee that something can
1900 * be built on the map, so the chance gets lower when the map is fuller, but there
1901 * is nothing we can really do about that. */
1902 if (deity_prospect || Random() <= indspec->prospecting_chance) {
1903 for (int i = 0; i < 5000; i++) {
1904 /* We should not have more than one Random() in a function call
1905 * because parameter evaluation order is not guaranteed in the c++ standard
1907 tile = RandomTile();
1908 /* Start with a random layout */
1909 int layout = RandomRange(num_layouts);
1910 /* Check now each layout, starting with the random one */
1911 for (int j = 0; j < num_layouts; j++) {
1912 layout = (layout + 1) % num_layouts;
1913 ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, cur_company.GetOriginalValue(), _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_PROSPECTCREATION, &ind);
1914 if (ret.Succeeded()) break;
1916 if (ret.Succeeded()) break;
1919 cur_company.Restore();
1921 } else {
1922 int layout = GB(p1, 8, 8);
1923 if (layout >= num_layouts) return CMD_ERROR;
1925 /* Check subsequently each layout, starting with the given layout in p1 */
1926 for (int i = 0; i < num_layouts; i++) {
1927 layout = (layout + 1) % num_layouts;
1928 ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, _current_company, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, &ind);
1929 if (ret.Succeeded()) break;
1932 /* If it still failed, there's no suitable layout to build here, return the error */
1933 if (ret.Failed()) return ret;
1936 if ((flags & DC_EXEC) && ind != NULL && _game_mode != GM_EDITOR) {
1937 AdvertiseIndustryOpening(ind);
1940 return CommandCost(EXPENSES_OTHER, indspec->GetConstructionCost());
1945 * Create a new industry of random layout.
1946 * @param tile The location to build the industry.
1947 * @param type The industry type to build.
1948 * @param creation_type The circumstances the industry is created under.
1949 * @return the created industry or NULL if it failed.
1951 static Industry *CreateNewIndustry(TileIndex tile, IndustryType type, IndustryAvailabilityCallType creation_type)
1953 const IndustrySpec *indspec = GetIndustrySpec(type);
1955 uint32 seed = Random();
1956 uint32 seed2 = Random();
1957 Industry *ind = NULL;
1958 CommandCost ret;
1960 int layout = RandomRange(indspec->num_table);
1962 /* Check subsequently each layout, starting with the given layout in p1 */
1963 for (int i = 0; i < indspec->num_table; i++) {
1964 layout = (layout + 1) % indspec->num_table;
1965 ret = CreateNewIndustryHelper(tile, type, DC_EXEC, indspec, layout, seed, GB(seed2, 0, 16), OWNER_NONE, creation_type, &ind);
1966 if (ret.Succeeded()) break;
1969 assert(ind != NULL || ret.Failed());
1970 return ind;
1974 * Compute the appearance probability for an industry during map creation.
1975 * @param it Industry type to compute.
1976 * @param [out] force_at_least_one Returns whether at least one instance should be forced on map creation.
1977 * @return Relative probability for the industry to appear.
1979 static uint32 GetScaledIndustryGenerationProbability(IndustryType it, bool *force_at_least_one)
1981 const IndustrySpec *ind_spc = GetIndustrySpec(it);
1982 uint32 chance = ind_spc->appear_creation[_settings_game.game_creation.landscape] * 16; // * 16 to increase precision
1983 if (!ind_spc->enabled || ind_spc->num_table == 0 ||
1984 (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == ID_FUND_ONLY) ||
1985 (chance = GetIndustryProbabilityCallback(it, IACT_MAPGENERATION, chance)) == 0) {
1986 *force_at_least_one = false;
1987 return 0;
1988 } else {
1989 /* We want industries appearing at coast to appear less often on bigger maps, as length of coast increases slower than map area.
1990 * For simplicity we scale in both cases, though scaling the probabilities of all industries has no effect. */
1991 chance = (ind_spc->check_proc == CHECK_REFINERY || ind_spc->check_proc == CHECK_OIL_RIG) ? ScaleByMapSize1D(chance) : ScaleByMapSize(chance);
1993 *force_at_least_one = (chance > 0) && !(ind_spc->behaviour & INDUSTRYBEH_NOBUILT_MAPCREATION) && (_game_mode != GM_EDITOR);
1994 return chance;
1999 * Compute the probability for constructing a new industry during game play.
2000 * @param it Industry type to compute.
2001 * @param [out] min_number Minimal number of industries that should exist at the map.
2002 * @return Relative probability for the industry to appear.
2004 static uint16 GetIndustryGamePlayProbability(IndustryType it, byte *min_number)
2006 if (_settings_game.difficulty.industry_density == ID_FUND_ONLY) {
2007 *min_number = 0;
2008 return 0;
2011 const IndustrySpec *ind_spc = GetIndustrySpec(it);
2012 byte chance = ind_spc->appear_ingame[_settings_game.game_creation.landscape];
2013 if (!ind_spc->enabled || ind_spc->num_table == 0 ||
2014 ((ind_spc->behaviour & INDUSTRYBEH_BEFORE_1950) && _cur_year > 1950) ||
2015 ((ind_spc->behaviour & INDUSTRYBEH_AFTER_1960) && _cur_year < 1960) ||
2016 (chance = GetIndustryProbabilityCallback(it, IACT_RANDOMCREATION, chance)) == 0) {
2017 *min_number = 0;
2018 return 0;
2020 *min_number = (ind_spc->behaviour & INDUSTRYBEH_CANCLOSE_LASTINSTANCE) ? 1 : 0;
2021 return chance;
2025 * Get wanted number of industries on the map.
2026 * @return Wanted number of industries at the map.
2028 static uint GetNumberOfIndustries()
2030 /* Number of industries on a 256x256 map. */
2031 static const uint16 numof_industry_table[] = {
2032 0, // none
2033 0, // minimal
2034 10, // very low
2035 25, // low
2036 55, // normal
2037 80, // high
2040 assert(lengthof(numof_industry_table) == ID_END);
2041 uint difficulty = (_game_mode != GM_EDITOR) ? _settings_game.difficulty.industry_density : (uint)ID_VERY_LOW;
2042 return min(IndustryPool::MAX_SIZE, ScaleByMapSize(numof_industry_table[difficulty]));
2046 * Try to place the industry in the game.
2047 * Since there is no feedback why placement fails, there is no other option
2048 * than to try a few times before concluding it does not work.
2049 * @param type Industry type of the desired industry.
2050 * @param try_hard Try very hard to find a place. (Used to place at least one industry per type.)
2051 * @return Pointer to created industry, or \c NULL if creation failed.
2053 static Industry *PlaceIndustry(IndustryType type, IndustryAvailabilityCallType creation_type, bool try_hard)
2055 uint tries = try_hard ? 25000u : 10000u;
2056 for (; tries > 0; tries--) {
2057 Industry *ind = CreateNewIndustry(RandomTile(), type, creation_type);
2058 if (ind != NULL) return ind;
2060 return NULL;
2064 * Try to build a industry on the map.
2065 * @param type IndustryType of the desired industry
2066 * @param try_hard Try very hard to find a place. (Used to place at least one industry per type)
2068 static void PlaceInitialIndustry(IndustryType type, bool try_hard)
2070 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
2072 IncreaseGeneratingWorldProgress(GWP_INDUSTRY);
2073 PlaceIndustry(type, IACT_MAPGENERATION, try_hard);
2075 cur_company.Restore();
2079 * Get total number of industries existing in the game.
2080 * @return Number of industries currently in the game.
2082 static uint GetCurrentTotalNumberOfIndustries()
2084 int total = 0;
2085 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) total += Industry::GetIndustryTypeCount(it);
2086 return total;
2090 /** Reset the entry. */
2091 void IndustryTypeBuildData::Reset()
2093 this->probability = 0;
2094 this->min_number = 0;
2095 this->target_count = 0;
2096 this->max_wait = 1;
2097 this->wait_count = 0;
2100 /** Completely reset the industry build data. */
2101 void IndustryBuildData::Reset()
2103 this->wanted_inds = GetCurrentTotalNumberOfIndustries() << 16;
2105 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2106 this->builddata[it].Reset();
2110 /** Monthly update of industry build data. */
2111 void IndustryBuildData::MonthlyLoop()
2113 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.
2114 if (_settings_game.difficulty.industry_density == ID_FUND_ONLY) return; // 'no industries' setting.
2116 /* To prevent running out of unused industries for the player to connect,
2117 * add a fraction of new industries each month, but only if the manager can keep up. */
2118 uint max_behind = 1 + min(99u, ScaleByMapSize(3)); // At most 2 industries for small maps, and 100 at the biggest map (about 6 months industry build attempts).
2119 if (GetCurrentTotalNumberOfIndustries() + max_behind >= (this->wanted_inds >> 16)) {
2120 this->wanted_inds += ScaleByMapSize(NEWINDS_PER_MONTH);
2125 * This function will create random industries during game creation.
2126 * It will scale the amount of industries by mapsize and difficulty level.
2128 void GenerateIndustries()
2130 if (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == ID_FUND_ONLY) return; // No industries in the game.
2132 uint32 industry_probs[NUM_INDUSTRYTYPES];
2133 bool force_at_least_one[NUM_INDUSTRYTYPES];
2134 uint32 total_prob = 0;
2135 uint num_forced = 0;
2137 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2138 industry_probs[it] = GetScaledIndustryGenerationProbability(it, force_at_least_one + it);
2139 total_prob += industry_probs[it];
2140 if (force_at_least_one[it]) num_forced++;
2143 uint total_amount = GetNumberOfIndustries();
2144 if (total_prob == 0 || total_amount < num_forced) {
2145 /* Only place the forced ones */
2146 total_amount = num_forced;
2149 SetGeneratingWorldProgress(GWP_INDUSTRY, total_amount);
2151 /* Try to build one industry per type independent of any probabilities */
2152 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2153 if (force_at_least_one[it]) {
2154 assert(total_amount > 0);
2155 total_amount--;
2156 PlaceInitialIndustry(it, true);
2160 /* Add the remaining industries according to their probabilities */
2161 for (uint i = 0; i < total_amount; i++) {
2162 uint32 r = RandomRange(total_prob);
2163 IndustryType it = 0;
2164 while (r >= industry_probs[it]) {
2165 r -= industry_probs[it];
2166 it++;
2167 assert(it < NUM_INDUSTRYTYPES);
2169 assert(industry_probs[it] > 0);
2170 PlaceInitialIndustry(it, false);
2172 _industry_builder.Reset();
2176 * Monthly update of industry statistics.
2177 * @param i Industry to update.
2179 static void UpdateIndustryStatistics(Industry *i)
2181 for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
2182 if (i->produced_cargo[j] != CT_INVALID) {
2183 byte pct = 0;
2184 if (i->this_month_production[j] != 0) {
2185 i->last_prod_year = _cur_year;
2186 pct = min(i->this_month_transported[j] * 256 / i->this_month_production[j], 255);
2188 i->last_month_pct_transported[j] = pct;
2190 i->last_month_production[j] = i->this_month_production[j];
2191 i->this_month_production[j] = 0;
2193 i->last_month_transported[j] = i->this_month_transported[j];
2194 i->this_month_transported[j] = 0;
2200 * Recompute #production_rate for current #prod_level.
2201 * This function is only valid when not using smooth economy.
2203 void Industry::RecomputeProductionMultipliers()
2205 const IndustrySpec *indspec = GetIndustrySpec(this->type);
2206 assert(!indspec->UsesSmoothEconomy());
2208 /* Rates are rounded up, so e.g. oilrig always produces some passengers */
2209 this->production_rate[0] = min(CeilDiv(indspec->production_rate[0] * this->prod_level, PRODLEVEL_DEFAULT), 0xFF);
2210 this->production_rate[1] = min(CeilDiv(indspec->production_rate[1] * this->prod_level, PRODLEVEL_DEFAULT), 0xFF);
2215 * Set the #probability and #min_number fields for the industry type \a it for a running game.
2216 * @param it Industry type.
2217 * @return At least one of the fields has changed value.
2219 bool IndustryTypeBuildData::GetIndustryTypeData(IndustryType it)
2221 byte min_number;
2222 uint32 probability = GetIndustryGamePlayProbability(it, &min_number);
2223 bool changed = min_number != this->min_number || probability != this->probability;
2224 this->min_number = min_number;
2225 this->probability = probability;
2226 return changed;
2229 /** Decide how many industries of each type are needed. */
2230 void IndustryBuildData::SetupTargetCount()
2232 bool changed = false;
2233 uint num_planned = 0; // Number of industries planned in the industry build data.
2234 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2235 changed |= this->builddata[it].GetIndustryTypeData(it);
2236 num_planned += this->builddata[it].target_count;
2238 uint total_amount = this->wanted_inds >> 16; // Desired total number of industries.
2239 changed |= num_planned != total_amount;
2240 if (!changed) return; // All industries are still the same, no need to re-randomize.
2242 /* Initialize the target counts. */
2243 uint force_build = 0; // Number of industries that should always be available.
2244 uint32 total_prob = 0; // Sum of probabilities.
2245 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2246 IndustryTypeBuildData *ibd = this->builddata + it;
2247 force_build += ibd->min_number;
2248 ibd->target_count = ibd->min_number;
2249 total_prob += ibd->probability;
2252 if (total_prob == 0) return; // No buildable industries.
2254 /* Subtract forced industries from the number of industries available for construction. */
2255 total_amount = (total_amount <= force_build) ? 0 : total_amount - force_build;
2257 /* Assign number of industries that should be aimed for, by using the probability as a weight. */
2258 while (total_amount > 0) {
2259 uint32 r = RandomRange(total_prob);
2260 IndustryType it = 0;
2261 while (r >= this->builddata[it].probability) {
2262 r -= this->builddata[it].probability;
2263 it++;
2264 assert(it < NUM_INDUSTRYTYPES);
2266 assert(this->builddata[it].probability > 0);
2267 this->builddata[it].target_count++;
2268 total_amount--;
2273 * Try to create a random industry, during gameplay
2275 void IndustryBuildData::TryBuildNewIndustry()
2277 this->SetupTargetCount();
2279 int missing = 0; // Number of industries that need to be build.
2280 uint count = 0; // Number of industry types eligible for build.
2281 uint32 total_prob = 0; // Sum of probabilities.
2282 IndustryType forced_build = NUM_INDUSTRYTYPES; // Industry type that should be forcibly build.
2283 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2284 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
2285 missing += difference;
2286 if (this->builddata[it].wait_count > 0) continue; // This type may not be built now.
2287 if (difference > 0) {
2288 if (Industry::GetIndustryTypeCount(it) == 0 && this->builddata[it].min_number > 0) {
2289 /* An industry that should exist at least once, is not available. Force it, trying the most needed one first. */
2290 if (forced_build == NUM_INDUSTRYTYPES ||
2291 difference > this->builddata[forced_build].target_count - Industry::GetIndustryTypeCount(forced_build)) {
2292 forced_build = it;
2295 total_prob += difference;
2296 count++;
2300 if (EconomyIsInRecession() || (forced_build == NUM_INDUSTRYTYPES && (missing <= 0 || total_prob == 0))) count = 0; // Skip creation of an industry.
2302 if (count >= 1) {
2303 /* If not forced, pick a weighted random industry to build.
2304 * For the case that count == 1, there is no need to draw a random number. */
2305 IndustryType it;
2306 if (forced_build != NUM_INDUSTRYTYPES) {
2307 it = forced_build;
2308 } else {
2309 /* Non-forced, select an industry type to build (weighted random). */
2310 uint32 r = 0; // Initialized to silence the compiler.
2311 if (count > 1) r = RandomRange(total_prob);
2312 for (it = 0; it < NUM_INDUSTRYTYPES; it++) {
2313 if (this->builddata[it].wait_count > 0) continue; // Type may not be built now.
2314 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
2315 if (difference <= 0) continue; // Too many of this kind.
2316 if (count == 1) break;
2317 if (r < (uint)difference) break;
2318 r -= difference;
2320 assert(it < NUM_INDUSTRYTYPES && this->builddata[it].target_count > Industry::GetIndustryTypeCount(it));
2323 /* Try to create the industry. */
2324 const Industry *ind = PlaceIndustry(it, IACT_RANDOMCREATION, forced_build != NUM_INDUSTRYTYPES);
2325 if (ind == NULL) {
2326 this->builddata[it].wait_count = this->builddata[it].max_wait + 1; // Compensate for decrementing below.
2327 this->builddata[it].max_wait = min(1000, this->builddata[it].max_wait + 2);
2328 } else {
2329 AdvertiseIndustryOpening(ind);
2330 this->builddata[it].max_wait = max(this->builddata[it].max_wait / 2, 1); // Reduce waiting time of the industry type.
2334 /* Decrement wait counters. */
2335 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2336 if (this->builddata[it].wait_count > 0) this->builddata[it].wait_count--;
2341 * Protects an industry from closure if the appropriate flags and conditions are met
2342 * INDUSTRYBEH_CANCLOSE_LASTINSTANCE must be set (which, by default, it is not) and the
2343 * count of industries of this type must one (or lower) in order to be protected
2344 * against closure.
2345 * @param type IndustryType been queried
2346 * @result true if protection is on, false otherwise (except for oil wells)
2348 static bool CheckIndustryCloseDownProtection(IndustryType type)
2350 const IndustrySpec *indspec = GetIndustrySpec(type);
2352 /* oil wells (or the industries with that flag set) are always allowed to closedown */
2353 if ((indspec->behaviour & INDUSTRYBEH_DONT_INCR_PROD) && _settings_game.game_creation.landscape == LT_TEMPERATE) return false;
2354 return (indspec->behaviour & INDUSTRYBEH_CANCLOSE_LASTINSTANCE) == 0 && Industry::GetIndustryTypeCount(type) <= 1;
2358 * Can given cargo type be accepted or produced by the industry?
2359 * @param cargo: Cargo type
2360 * @param ind: Industry
2361 * @param *c_accepts: Pointer to boolean for acceptance of cargo
2362 * @param *c_produces: Pointer to boolean for production of cargo
2363 * @return: \c *c_accepts is set when industry accepts the cargo type,
2364 * \c *c_produces is set when the industry produces the cargo type
2366 static void CanCargoServiceIndustry(CargoID cargo, Industry *ind, bool *c_accepts, bool *c_produces)
2368 if (cargo == CT_INVALID) return;
2370 /* Check for acceptance of cargo */
2371 for (byte j = 0; j < lengthof(ind->accepts_cargo); j++) {
2372 if (cargo == ind->accepts_cargo[j] && !IndustryTemporarilyRefusesCargo(ind, cargo)) {
2373 *c_accepts = true;
2374 break;
2378 /* Check for produced cargo */
2379 for (byte j = 0; j < lengthof(ind->produced_cargo); j++) {
2380 if (cargo == ind->produced_cargo[j]) {
2381 *c_produces = true;
2382 break;
2388 * Compute who can service the industry.
2390 * Here, 'can service' means that he/she has trains and stations close enough
2391 * to the industry with the right cargo type and the right orders (ie has the
2392 * technical means).
2394 * @param ind: Industry being investigated.
2396 * @return: 0 if nobody can service the industry, 2 if the local company can
2397 * service the industry, and 1 otherwise (only competitors can service the
2398 * industry)
2400 static int WhoCanServiceIndustry(Industry *ind)
2402 /* Find all stations within reach of the industry */
2403 StationList stations;
2404 FindStationsAroundTiles(ind->location, &stations);
2406 if (stations.Length() == 0) return 0; // No stations found at all => nobody services
2408 const Vehicle *v;
2409 int result = 0;
2410 FOR_ALL_VEHICLES(v) {
2411 /* Is it worthwhile to try this vehicle? */
2412 if (v->owner != _local_company && result != 0) continue;
2414 /* Check whether it accepts the right kind of cargo */
2415 bool c_accepts = false;
2416 bool c_produces = false;
2417 if (v->type == VEH_TRAIN && v->IsFrontEngine()) {
2418 for (const Vehicle *u = v; u != NULL; u = u->Next()) {
2419 CanCargoServiceIndustry(u->cargo_type, ind, &c_accepts, &c_produces);
2421 } else if (v->type == VEH_ROAD || v->type == VEH_SHIP || v->type == VEH_AIRCRAFT) {
2422 CanCargoServiceIndustry(v->cargo_type, ind, &c_accepts, &c_produces);
2423 } else {
2424 continue;
2426 if (!c_accepts && !c_produces) continue; // Wrong cargo
2428 /* Check orders of the vehicle.
2429 * We cannot check the first of shared orders only, since the first vehicle in such a chain
2430 * may have a different cargo type.
2432 const Order *o;
2433 FOR_VEHICLE_ORDERS(v, o) {
2434 if (o->IsType(OT_GOTO_STATION) && !(o->GetUnloadType() & OUFB_TRANSFER)) {
2435 /* Vehicle visits a station to load or unload */
2436 Station *st = Station::Get(o->GetDestination());
2437 assert(st != NULL);
2439 /* Same cargo produced by industry is dropped here => not serviced by vehicle v */
2440 if ((o->GetUnloadType() & OUFB_UNLOAD) && !c_accepts) break;
2442 if (stations.Contains(st)) {
2443 if (v->owner == _local_company) return 2; // Company services industry
2444 result = 1; // Competitor services industry
2449 return result;
2453 * Report news that industry production has changed significantly
2455 * @param ind: Industry with changed production
2456 * @param type: Cargo type that has changed
2457 * @param percent: Percentage of change (>0 means increase, <0 means decrease)
2459 static void ReportNewsProductionChangeIndustry(Industry *ind, CargoID type, int percent)
2461 NewsType nt;
2463 switch (WhoCanServiceIndustry(ind)) {
2464 case 0: nt = NT_INDUSTRY_NOBODY; break;
2465 case 1: nt = NT_INDUSTRY_OTHER; break;
2466 case 2: nt = NT_INDUSTRY_COMPANY; break;
2467 default: NOT_REACHED();
2469 SetDParam(2, abs(percent));
2470 SetDParam(0, CargoSpec::Get(type)->name);
2471 SetDParam(1, ind->index);
2472 AddIndustryNewsItem(
2473 percent >= 0 ? STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH : STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH,
2475 ind->index
2479 static const uint PERCENT_TRANSPORTED_60 = 153;
2480 static const uint PERCENT_TRANSPORTED_80 = 204;
2483 * Change industry production or do closure
2484 * @param i Industry for which changes are performed
2485 * @param monthly true if it's the monthly call, false if it's the random call
2487 static void ChangeIndustryProduction(Industry *i, bool monthly)
2489 StringID str = STR_NULL;
2490 bool closeit = false;
2491 const IndustrySpec *indspec = GetIndustrySpec(i->type);
2492 bool standard = false;
2493 bool suppress_message = false;
2494 bool recalculate_multipliers = false; ///< reinitialize production_rate to match prod_level
2495 /* don't use smooth economy for industries using production related callbacks */
2496 bool smooth_economy = indspec->UsesSmoothEconomy();
2497 byte div = 0;
2498 byte mul = 0;
2499 int8 increment = 0;
2501 bool callback_enabled = HasBit(indspec->callback_mask, monthly ? CBM_IND_MONTHLYPROD_CHANGE : CBM_IND_PRODUCTION_CHANGE);
2502 if (callback_enabled) {
2503 uint16 res = GetIndustryCallback(monthly ? CBID_INDUSTRY_MONTHLYPROD_CHANGE : CBID_INDUSTRY_PRODUCTION_CHANGE, 0, Random(), i, i->type, i->location.tile);
2504 if (res != CALLBACK_FAILED) { // failed callback means "do nothing"
2505 suppress_message = HasBit(res, 7);
2506 /* Get the custom message if any */
2507 if (HasBit(res, 8)) str = MapGRFStringID(indspec->grf_prop.grffile->grfid, GB(GetRegister(0x100), 0, 16));
2508 res = GB(res, 0, 4);
2509 switch (res) {
2510 default: NOT_REACHED();
2511 case 0x0: break; // Do nothing, but show the custom message if any
2512 case 0x1: div = 1; break; // Halve industry production. If production reaches the quarter of the default, the industry is closed instead.
2513 case 0x2: mul = 1; break; // Double industry production if it hasn't reached eight times of the original yet.
2514 case 0x3: closeit = true; break; // The industry announces imminent closure, and is physically removed from the map next month.
2515 case 0x4: standard = true; break; // Do the standard random production change as if this industry was a primary one.
2516 case 0x5: case 0x6: case 0x7: // Divide production by 4, 8, 16
2517 case 0x8: div = res - 0x3; break; // Divide production by 32
2518 case 0x9: case 0xA: case 0xB: // Multiply production by 4, 8, 16
2519 case 0xC: mul = res - 0x7; break; // Multiply production by 32
2520 case 0xD: // decrement production
2521 case 0xE: // increment production
2522 increment = res == 0x0D ? -1 : 1;
2523 break;
2524 case 0xF: // Set production to third byte of register 0x100
2525 i->prod_level = Clamp(GB(GetRegister(0x100), 16, 8), PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
2526 recalculate_multipliers = true;
2527 break;
2530 } else {
2531 if (monthly != smooth_economy) return;
2532 if (indspec->life_type == INDUSTRYLIFE_BLACK_HOLE) return;
2535 if (standard || (!callback_enabled && (indspec->life_type & (INDUSTRYLIFE_ORGANIC | INDUSTRYLIFE_EXTRACTIVE)) != 0)) {
2536 /* decrease or increase */
2537 bool only_decrease = (indspec->behaviour & INDUSTRYBEH_DONT_INCR_PROD) && _settings_game.game_creation.landscape == LT_TEMPERATE;
2539 if (smooth_economy) {
2540 closeit = true;
2541 for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
2542 if (i->produced_cargo[j] == CT_INVALID) continue;
2543 uint32 r = Random();
2544 int old_prod, new_prod, percent;
2545 /* If over 60% is transported, mult is 1, else mult is -1. */
2546 int mult = (i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_60) ? 1 : -1;
2548 new_prod = old_prod = i->production_rate[j];
2550 /* For industries with only_decrease flags (temperate terrain Oil Wells),
2551 * the multiplier will always be -1 so they will only decrease. */
2552 if (only_decrease) {
2553 mult = -1;
2554 /* For normal industries, if over 60% is transported, 33% chance for decrease.
2555 * Bonus for very high station ratings (over 80%): 16% chance for decrease. */
2556 } else if (Chance16I(1, ((i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_80) ? 6 : 3), r)) {
2557 mult *= -1;
2560 /* 4.5% chance for 3-23% (or 1 unit for very low productions) production change,
2561 * determined by mult value. If mult = 1 prod. increases, else (-1) it decreases. */
2562 if (Chance16I(1, 22, r >> 16)) {
2563 new_prod += mult * (max(((RandomRange(50) + 10) * old_prod) >> 8, 1U));
2566 /* Prevent production to overflow or Oil Rig passengers to be over-"produced" */
2567 new_prod = Clamp(new_prod, 1, 255);
2569 if (((indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0) && j == 1) {
2570 new_prod = Clamp(new_prod, 0, 16);
2573 /* Do not stop closing the industry when it has the lowest possible production rate */
2574 if (new_prod == old_prod && old_prod > 1) {
2575 closeit = false;
2576 continue;
2579 percent = (old_prod == 0) ? 100 : (new_prod * 100 / old_prod - 100);
2580 i->production_rate[j] = new_prod;
2582 /* Close the industry when it has the lowest possible production rate */
2583 if (new_prod > 1) closeit = false;
2585 if (abs(percent) >= 10) {
2586 ReportNewsProductionChangeIndustry(i, i->produced_cargo[j], percent);
2589 } else {
2590 if (only_decrease || Chance16(1, 3)) {
2591 /* If more than 60% transported, 66% chance of increase, else 33% chance of increase */
2592 if (!only_decrease && (i->last_month_pct_transported[0] > PERCENT_TRANSPORTED_60) != Chance16(1, 3)) {
2593 mul = 1; // Increase production
2594 } else {
2595 div = 1; // Decrease production
2601 if (!callback_enabled && (indspec->life_type & INDUSTRYLIFE_PROCESSING)) {
2602 if ( (byte)(_cur_year - i->last_prod_year) >= 5 && Chance16(1, smooth_economy ? 180 : 2)) {
2603 closeit = true;
2607 /* Increase if needed */
2608 while (mul-- != 0 && i->prod_level < PRODLEVEL_MAXIMUM) {
2609 i->prod_level = min(i->prod_level * 2, PRODLEVEL_MAXIMUM);
2610 recalculate_multipliers = true;
2611 if (str == STR_NULL) str = indspec->production_up_text;
2614 /* Decrease if needed */
2615 while (div-- != 0 && !closeit) {
2616 if (i->prod_level == PRODLEVEL_MINIMUM) {
2617 closeit = true;
2618 } else {
2619 i->prod_level = max(i->prod_level / 2, (int)PRODLEVEL_MINIMUM); // typecast to int required to please MSVC
2620 recalculate_multipliers = true;
2621 if (str == STR_NULL) str = indspec->production_down_text;
2625 /* Increase or Decreasing the production level if needed */
2626 if (increment != 0) {
2627 if (increment < 0 && i->prod_level == PRODLEVEL_MINIMUM) {
2628 closeit = true;
2629 } else {
2630 i->prod_level = ClampU(i->prod_level + increment, PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
2631 recalculate_multipliers = true;
2635 /* Recalculate production_rate
2636 * For non-smooth economy these should always be synchronized with prod_level */
2637 if (recalculate_multipliers) i->RecomputeProductionMultipliers();
2639 /* Close if needed and allowed */
2640 if (closeit && !CheckIndustryCloseDownProtection(i->type)) {
2641 i->prod_level = PRODLEVEL_CLOSURE;
2642 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
2643 str = indspec->closure_text;
2646 if (!suppress_message && str != STR_NULL) {
2647 NewsType nt;
2648 /* Compute news category */
2649 if (closeit) {
2650 nt = NT_INDUSTRY_CLOSE;
2651 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index));
2652 Game::NewEvent(new ScriptEventIndustryClose(i->index));
2653 } else {
2654 switch (WhoCanServiceIndustry(i)) {
2655 case 0: nt = NT_INDUSTRY_NOBODY; break;
2656 case 1: nt = NT_INDUSTRY_OTHER; break;
2657 case 2: nt = NT_INDUSTRY_COMPANY; break;
2658 default: NOT_REACHED();
2661 /* Set parameters of news string */
2662 if (str > STR_LAST_STRINGID) {
2663 SetDParam(0, STR_TOWN_NAME);
2664 SetDParam(1, i->town->index);
2665 SetDParam(2, indspec->name);
2666 } else if (closeit) {
2667 SetDParam(0, STR_FORMAT_INDUSTRY_NAME);
2668 SetDParam(1, i->town->index);
2669 SetDParam(2, indspec->name);
2670 } else {
2671 SetDParam(0, i->index);
2673 /* and report the news to the user */
2674 if (closeit) {
2675 AddTileNewsItem(str, nt, i->location.tile + TileDiffXY(1, 1));
2676 } else {
2677 AddIndustryNewsItem(str, nt, i->index);
2683 * Daily handler for the industry changes
2684 * Taking the original map size of 256*256, the number of random changes was always of just one unit.
2685 * But it cannot be the same on smaller or bigger maps. That number has to be scaled up or down.
2686 * For small maps, it implies that less than one change per month is required, while on bigger maps,
2687 * it would be way more. The daily loop handles those changes.
2689 void IndustryDailyLoop()
2691 _economy.industry_daily_change_counter += _economy.industry_daily_increment;
2693 /* Bits 16-31 of industry_construction_counter contain the number of industries to change/create today,
2694 * the lower 16 bit are a fractional part that might accumulate over several days until it
2695 * is sufficient for an industry. */
2696 uint16 change_loop = _economy.industry_daily_change_counter >> 16;
2698 /* Reset the active part of the counter, just keeping the "fractional part" */
2699 _economy.industry_daily_change_counter &= 0xFFFF;
2701 if (change_loop == 0) {
2702 return; // Nothing to do? get out
2705 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
2707 /* perform the required industry changes for the day */
2709 uint perc = 3; // Between 3% and 9% chance of creating a new industry.
2710 if ((_industry_builder.wanted_inds >> 16) > GetCurrentTotalNumberOfIndustries()) {
2711 perc = min(9u, perc + (_industry_builder.wanted_inds >> 16) - GetCurrentTotalNumberOfIndustries());
2713 for (uint16 j = 0; j < change_loop; j++) {
2714 /* industry for taxes */
2715 if (_economy.industry_helper > _price[PR_BUILD_INDUSTRY] << 3) {
2716 _economy.industry_helper -= _price[PR_BUILD_INDUSTRY] << 3;
2717 _industry_builder.TryBuildNewIndustry();
2718 } else if (Chance16(3, 100)) {
2719 _industry_builder.TryBuildNewIndustry();
2720 } else {
2721 Industry *i = Industry::GetRandom();
2722 if (i != NULL) {
2723 ChangeIndustryProduction(i, false);
2724 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
2729 cur_company.Restore();
2731 /* production-change */
2732 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 1);
2735 void IndustryMonthlyLoop()
2737 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
2739 _industry_builder.MonthlyLoop();
2741 Industry *i;
2742 FOR_ALL_INDUSTRIES(i) {
2743 UpdateIndustryStatistics(i);
2744 if (i->prod_level == PRODLEVEL_CLOSURE) {
2745 delete i;
2746 } else {
2747 ChangeIndustryProduction(i, true);
2748 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
2752 cur_company.Restore();
2754 /* production-change */
2755 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 1);
2759 void InitializeIndustries()
2761 Industry::ResetIndustryCounts();
2762 _industry_sound_tile = 0;
2764 _industry_builder.Reset();
2767 /** Verify whether the generated industries are complete, and warn the user if not. */
2768 void CheckIndustries()
2770 int count = 0;
2771 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2772 if (Industry::GetIndustryTypeCount(it) > 0) continue; // Types of existing industries can be skipped.
2774 bool force_at_least_one;
2775 uint32 chance = GetScaledIndustryGenerationProbability(it, &force_at_least_one);
2776 if (chance == 0 || !force_at_least_one) continue; // Types that are not available can be skipped.
2778 const IndustrySpec *is = GetIndustrySpec(it);
2779 SetDParam(0, is->name);
2780 ShowErrorMessage(STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES, STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION, WL_WARNING);
2782 count++;
2783 if (count >= 3) break; // Don't swamp the user with errors.
2788 * Is an industry with the spec a raw industry?
2789 * @return true if it should be handled as a raw industry
2791 bool IndustrySpec::IsRawIndustry() const
2793 return (this->life_type & (INDUSTRYLIFE_EXTRACTIVE | INDUSTRYLIFE_ORGANIC)) != 0;
2797 * Is an industry with the spec a processing industry?
2798 * @return true if it should be handled as a processing industry
2800 bool IndustrySpec::IsProcessingIndustry() const
2802 /* Lumber mills are neither raw nor processing */
2803 return (this->life_type & INDUSTRYLIFE_PROCESSING) != 0 &&
2804 (this->behaviour & INDUSTRYBEH_CUT_TREES) == 0;
2808 * Get the cost for constructing this industry
2809 * @return the cost (inflation corrected etc)
2811 Money IndustrySpec::GetConstructionCost() const
2813 /* Building raw industries like secondary uses different price base */
2814 return (_price[(_settings_game.construction.raw_industry_construction == 1 && this->IsRawIndustry()) ?
2815 PR_BUILD_INDUSTRY_RAW : PR_BUILD_INDUSTRY] * this->cost_multiplier) >> 8;
2819 * Get the cost for removing this industry
2820 * Take note that the cost will always be zero for non-grf industries.
2821 * Only if the grf author did specified a cost will it be applicable.
2822 * @return the cost (inflation corrected etc)
2824 Money IndustrySpec::GetRemovalCost() const
2826 return (_price[PR_CLEAR_INDUSTRY] * this->removal_cost_multiplier) >> 8;
2830 * Determines whether this industrytype uses smooth economy or whether it uses standard/newgrf production changes.
2831 * @return true if smooth economy is used.
2833 bool IndustrySpec::UsesSmoothEconomy() const
2835 return _settings_game.economy.smooth_economy &&
2836 !(HasBit(this->callback_mask, CBM_IND_PRODUCTION_256_TICKS) || HasBit(this->callback_mask, CBM_IND_PRODUCTION_CARGO_ARRIVAL)) && // production callbacks
2837 !(HasBit(this->callback_mask, CBM_IND_MONTHLYPROD_CHANGE) || HasBit(this->callback_mask, CBM_IND_PRODUCTION_CHANGE) || HasBit(this->callback_mask, CBM_IND_PROD_CHANGE_BUILD)); // production change callbacks
2840 static CommandCost TerraformTile_Industry(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
2842 if (AutoslopeEnabled()) {
2843 /* We imitate here TTDP's behaviour:
2844 * - Both new and old slope must not be steep.
2845 * - TileMaxZ must not be changed.
2846 * - Allow autoslope by default.
2847 * - Disallow autoslope if callback succeeds and returns non-zero.
2849 Slope tileh_old = GetTileSlope(tile);
2850 /* TileMaxZ must not be changed. Slopes must not be steep. */
2851 if (!IsSteepSlope(tileh_old) && !IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) {
2852 const IndustryGfx gfx = GetIndustryGfx(tile);
2853 const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
2855 /* Call callback 3C 'disable autosloping for industry tiles'. */
2856 if (HasBit(itspec->callback_mask, CBM_INDT_AUTOSLOPE)) {
2857 /* If the callback fails, allow autoslope. */
2858 uint16 res = GetIndustryTileCallback(CBID_INDTILE_AUTOSLOPE, 0, 0, gfx, Industry::GetByTile(tile), tile);
2859 if (res == CALLBACK_FAILED || !ConvertBooleanCallback(itspec->grf_prop.grffile, CBID_INDTILE_AUTOSLOPE, res)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
2860 } else {
2861 /* allow autoslope */
2862 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
2866 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
2869 extern const TileTypeProcs _tile_type_industry_procs = {
2870 DrawTile_Industry, // draw_tile_proc
2871 GetSlopePixelZ_Industry, // get_slope_z_proc
2872 ClearTile_Industry, // clear_tile_proc
2873 AddAcceptedCargo_Industry, // add_accepted_cargo_proc
2874 GetTileDesc_Industry, // get_tile_desc_proc
2875 GetTileTrackStatus_Industry, // get_tile_track_status_proc
2876 ClickTile_Industry, // click_tile_proc
2877 AnimateTile_Industry, // animate_tile_proc
2878 TileLoop_Industry, // tile_loop_proc
2879 ChangeTileOwner_Industry, // change_tile_owner_proc
2880 NULL, // add_produced_cargo_proc
2881 NULL, // vehicle_enter_tile_proc
2882 GetFoundation_Industry, // get_foundation_proc
2883 TerraformTile_Industry, // terraform_tile_proc