Add a method in NewGRFInspectWindow to resolve FeatureIndex
[openttd/fttd.git] / src / industry_cmd.cpp
blob4ab1665d5c411b22856b883733d4ea6b49d287cb
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 "map/ground.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 "newgrf_cargo.h"
24 #include "newgrf_debug.h"
25 #include "newgrf_industrytiles.h"
26 #include "autoslope.h"
27 #include "water.h"
28 #include "strings_func.h"
29 #include "window_func.h"
30 #include "date_func.h"
31 #include "vehicle_func.h"
32 #include "sound_func.h"
33 #include "animated_tile_func.h"
34 #include "effectvehicle_func.h"
35 #include "effectvehicle_base.h"
36 #include "ai/ai.hpp"
37 #include "core/pool_func.hpp"
38 #include "subsidy_func.h"
39 #include "core/backup_type.hpp"
40 #include "object_base.h"
41 #include "game/game.hpp"
42 #include "station_func.h"
44 #include "table/strings.h"
45 #include "table/industry_land.h"
46 #include "table/build_industry.h"
48 IndustryPool _industry_pool("Industry");
49 INSTANTIATE_POOL_METHODS(Industry)
51 void ShowIndustryViewWindow(int industry);
52 void BuildOilRig(TileIndex tile);
54 static byte _industry_sound_ctr;
55 static TileIndex _industry_sound_tile;
57 uint16 Industry::counts[NUM_INDUSTRYTYPES];
59 IndustrySpec _industry_specs[NUM_INDUSTRYTYPES];
60 IndustryTileSpec _industry_tile_specs[NUM_INDUSTRYTILES];
61 IndustryBuildData _industry_builder; ///< In-game manager of industries.
63 /**
64 * This function initialize the spec arrays of both
65 * industry and industry tiles.
66 * It adjusts the enabling of the industry too, based on climate availability.
67 * This will allow for clearer testings
69 void ResetIndustries()
71 memset(&_industry_specs, 0, sizeof(_industry_specs));
72 memcpy(&_industry_specs, &_origin_industry_specs, sizeof(_origin_industry_specs));
74 /* once performed, enable only the current climate industries */
75 for (IndustryType i = 0; i < NUM_INDUSTRYTYPES; i++) {
76 _industry_specs[i].enabled = i < NEW_INDUSTRYOFFSET &&
77 HasBit(_origin_industry_specs[i].climate_availability, _settings_game.game_creation.landscape);
80 memset(&_industry_tile_specs, 0, sizeof(_industry_tile_specs));
81 memcpy(&_industry_tile_specs, &_origin_industry_tile_specs, sizeof(_origin_industry_tile_specs));
83 /* Reset any overrides that have been set. */
84 _industile_mngr.ResetOverride();
85 _industry_mngr.ResetOverride();
88 /**
89 * Retrieve the type for this industry. Although it is accessed by a tile,
90 * it will return the general type of industry, and not the sprite index
91 * as would do GetIndustryGfx.
92 * @param tile that is queried
93 * @pre IsIndustryTile(tile)
94 * @return general type for this industry, as defined in industry.h
96 IndustryType GetIndustryType(TileIndex tile)
98 assert(IsIndustryTile(tile));
100 const Industry *ind = Industry::GetByTile(tile);
101 assert(ind != NULL);
102 return ind->type;
106 * Accessor for array _industry_specs.
107 * This will ensure at once : proper access and
108 * not allowing modifications of it.
109 * @param thistype of industry (which is the index in _industry_specs)
110 * @pre thistype < NUM_INDUSTRYTYPES
111 * @return a pointer to the corresponding industry spec
113 const IndustrySpec *GetIndustrySpec(IndustryType thistype)
115 assert(thistype < NUM_INDUSTRYTYPES);
116 return &_industry_specs[thistype];
120 * Accessor for array _industry_tile_specs.
121 * This will ensure at once : proper access and
122 * not allowing modifications of it.
123 * @param gfx of industrytile (which is the index in _industry_tile_specs)
124 * @pre gfx < INVALID_INDUSTRYTILE
125 * @return a pointer to the corresponding industrytile spec
127 const IndustryTileSpec *GetIndustryTileSpec(IndustryGfx gfx)
129 assert(gfx < INVALID_INDUSTRYTILE);
130 return &_industry_tile_specs[gfx];
133 Industry::~Industry()
135 if (CleaningPool()) return;
137 /* Industry can also be destroyed when not fully initialized.
138 * This means that we do not have to clear tiles either.
139 * Also we must not decrement industry counts in that case. */
140 if (this->location.w == 0) return;
142 TILE_AREA_LOOP(tile_cur, this->location) {
143 if (IsIndustryTile(tile_cur)) {
144 if (GetIndustryIndex(tile_cur) == this->index) {
145 DeleteNewGRFInspectWindow(GSF_INDUSTRYTILES, tile_cur);
147 /* MakeWaterKeepingClass() can also handle 'land' */
148 MakeWaterKeepingClass(tile_cur, OWNER_NONE);
150 } else if (IsStationTile(tile_cur) && IsOilRig(tile_cur)) {
151 DeleteOilRig(tile_cur);
155 if (GetIndustrySpec(this->type)->behaviour & INDUSTRYBEH_PLANT_FIELDS) {
156 TileArea ta(this->location.tile - TileDiffXY(min(TileX(this->location.tile), 21), min(TileY(this->location.tile), 21)), 42, 42);
157 ta.ClampToMap();
159 /* Remove the farmland and convert it to regular tiles over time. */
160 TILE_AREA_LOOP(tile_cur, ta) {
161 if (IsFieldsTile(tile_cur) &&
162 GetIndustryIndexOfField(tile_cur) == this->index) {
163 SetIndustryIndexOfField(tile_cur, INVALID_INDUSTRY);
168 /* don't let any disaster vehicle target invalid industry */
169 ReleaseDisastersTargetingIndustry(this->index);
171 /* Clear the persistent storage. */
172 delete this->psa;
174 DecIndustryTypeCount(this->type);
176 DeleteIndustryNews(this->index);
177 DeleteWindowById(WC_INDUSTRY_VIEW, this->index);
178 DeleteNewGRFInspectWindow(GSF_INDUSTRIES, this->index);
180 DeleteSubsidyWith(ST_INDUSTRY, this->index);
181 CargoPacket::InvalidateAllFrom(ST_INDUSTRY, this->index);
185 * Invalidating some stuff after removing item from the pool.
186 * @param index index of deleted item
188 void Industry::PostDestructor(size_t index)
190 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0);
191 Station::RecomputeIndustriesNearForAll();
196 * Return a random valid industry.
197 * @return random industry, NULL if there are no industries
199 /* static */ Industry *Industry::GetRandom()
201 if (Industry::GetNumItems() == 0) return NULL;
202 int num = RandomRange((uint16)Industry::GetNumItems());
203 size_t index = MAX_UVALUE(size_t);
205 while (num >= 0) {
206 num--;
207 index++;
209 /* Make sure we have a valid industry */
210 while (!Industry::IsValidID(index)) {
211 index++;
212 assert(index < Industry::GetPoolSize());
216 return Industry::Get(index);
220 static void IndustryDrawSugarMine(const TileInfo *ti)
222 if (!IsIndustryCompleted(ti->tile)) return;
224 const DrawIndustryAnimationStruct *d = &_draw_industry_spec1[GetAnimationFrame(ti->tile)];
226 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_SIEVE + d->image_1, PAL_NONE, d->x, 0);
228 if (d->image_2 != 0) {
229 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_CLOUDS + d->image_2 - 1, PAL_NONE, 8, 41);
232 if (d->image_3 != 0) {
233 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_PILE + d->image_3 - 1, PAL_NONE,
234 _drawtile_proc1[d->image_3 - 1].x, _drawtile_proc1[d->image_3 - 1].y);
238 static void IndustryDrawToffeeQuarry(const TileInfo *ti)
240 uint8 x = 0;
242 if (IsIndustryCompleted(ti->tile)) {
243 x = _industry_anim_offs_toffee[GetAnimationFrame(ti->tile)];
244 if (x == 0xFF) {
245 x = 0;
249 AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_SHOVEL, PAL_NONE, 22 - x, 24 + x);
250 AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_TOFFEE, PAL_NONE, 6, 14);
253 static void IndustryDrawBubbleGenerator( const TileInfo *ti)
255 if (IsIndustryCompleted(ti->tile)) {
256 AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_BUBBLE, PAL_NONE, 5, _industry_anim_offs_bubbles[GetAnimationFrame(ti->tile)]);
258 AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_SPRING, PAL_NONE, 3, 67);
261 static void IndustryDrawToyFactory(const TileInfo *ti)
263 const DrawIndustryAnimationStruct *d = &_industry_anim_offs_toys[GetAnimationFrame(ti->tile)];
265 if (d->image_1 != 0xFF) {
266 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_CLAY, PAL_NONE, d->x, 96 + d->image_1);
269 if (d->image_2 != 0xFF) {
270 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_ROBOT, PAL_NONE, 16 - d->image_2 * 2, 100 + d->image_2);
273 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP, PAL_NONE, 7, d->image_3);
274 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP_HOLDER, PAL_NONE, 0, 42);
277 static void IndustryDrawCoalPlantSparks(const TileInfo *ti)
279 if (IsIndustryCompleted(ti->tile)) {
280 uint8 image = GetAnimationFrame(ti->tile);
282 if (image != 0 && image < 7) {
283 AddChildSpriteScreen(image + SPR_IT_POWER_PLANT_TRANSFORMERS,
284 PAL_NONE,
285 _coal_plant_sparks[image - 1].x,
286 _coal_plant_sparks[image - 1].y
292 typedef void IndustryDrawTileProc(const TileInfo *ti);
293 static IndustryDrawTileProc * const _industry_draw_tile_procs[5] = {
294 IndustryDrawSugarMine,
295 IndustryDrawToffeeQuarry,
296 IndustryDrawBubbleGenerator,
297 IndustryDrawToyFactory,
298 IndustryDrawCoalPlantSparks,
301 static void DrawTile_Industry(TileInfo *ti)
303 IndustryGfx gfx = GetIndustryGfx(ti->tile);
304 Industry *ind = Industry::GetByTile(ti->tile);
305 const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
307 /* Retrieve pointer to the draw industry tile struct */
308 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
309 /* Draw the tile using the specialized method of newgrf industrytile.
310 * DrawNewIndustry will return false if ever the resolver could not
311 * find any sprite to display. So in this case, we will jump on the
312 * substitute gfx instead. */
313 if (indts->grf_prop.spritegroup[0] != NULL && DrawNewIndustryTile(ti, ind, gfx, indts)) {
314 return;
315 } else {
316 /* No sprite group (or no valid one) found, meaning no graphics associated.
317 * Use the substitute one instead */
318 if (indts->grf_prop.subst_id != INVALID_INDUSTRYTILE) {
319 gfx = indts->grf_prop.subst_id;
320 /* And point the industrytile spec accordingly */
321 indts = GetIndustryTileSpec(gfx);
326 const DrawBuildingsTileStruct *dits = &_industry_draw_tile_data[gfx << 2 | (indts->anim_state ?
327 GetAnimationFrame(ti->tile) & INDUSTRY_COMPLETED :
328 GetIndustryConstructionStage(ti->tile))];
330 SpriteID image = dits->ground.sprite;
332 /* DrawFoundation() modifies ti->z and ti->tileh */
333 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
335 /* If the ground sprite is the default flat water sprite, draw also canal/river borders.
336 * Do not do this if the tile's WaterClass is 'land'. */
337 if (image == SPR_FLAT_WATER_TILE && IsTileOnWater(ti->tile)) {
338 DrawWaterClassGround(ti);
339 } else {
340 DrawGroundSprite(image, GroundSpritePaletteTransform(image, dits->ground.pal, GENERAL_SPRITE_COLOUR(ind->random_colour)));
343 /* If industries are transparent and invisible, do not draw the upper part */
344 if (IsInvisibilitySet(TO_INDUSTRIES)) return;
346 /* Add industry on top of the ground? */
347 image = dits->building.sprite;
348 if (image != 0) {
349 AddSortableSpriteToDraw(image, SpriteLayoutPaletteTransform(image, dits->building.pal, GENERAL_SPRITE_COLOUR(ind->random_colour)),
350 ti->x + dits->subtile_x,
351 ti->y + dits->subtile_y,
352 dits->width,
353 dits->height,
354 dits->dz,
355 ti->z,
356 IsTransparencySet(TO_INDUSTRIES));
358 if (IsTransparencySet(TO_INDUSTRIES)) return;
362 int proc = dits->draw_proc - 1;
363 if (proc >= 0) _industry_draw_tile_procs[proc](ti);
367 static int GetSlopePixelZ_Industry(TileIndex tile, uint x, uint y)
369 return GetTileMaxPixelZ(tile);
372 static Foundation GetFoundation_Industry(TileIndex tile, Slope tileh)
374 IndustryGfx gfx = GetIndustryGfx(tile);
376 /* For NewGRF industry tiles we might not be drawing a foundation. We need to
377 * account for this, as other structures should
378 * draw the wall of the foundation in this case.
380 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
381 const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
382 if (indts->grf_prop.spritegroup[0] != NULL && HasBit(indts->callback_mask, CBM_INDT_DRAW_FOUNDATIONS)) {
383 uint32 callback_res = GetIndustryTileCallback(CBID_INDTILE_DRAW_FOUNDATIONS, 0, 0, gfx, Industry::GetByTile(tile), tile);
384 if (callback_res != CALLBACK_FAILED && !ConvertBooleanCallback(indts->grf_prop.grffile, CBID_INDTILE_DRAW_FOUNDATIONS, callback_res)) return FOUNDATION_NONE;
387 return FlatteningFoundation(tileh);
390 static void AddAcceptedCargo_Industry(TileIndex tile, CargoArray &acceptance, uint32 *always_accepted)
392 IndustryGfx gfx = GetIndustryGfx(tile);
393 const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
395 /* When we have to use a callback, we put our data in the next two variables */
396 CargoID raw_accepts_cargo[lengthof(itspec->accepts_cargo)];
397 uint8 raw_cargo_acceptance[lengthof(itspec->acceptance)];
399 /* And then these will always point to a same sized array with the required data */
400 const CargoID *accepts_cargo = itspec->accepts_cargo;
401 const uint8 *cargo_acceptance = itspec->acceptance;
403 if (HasBit(itspec->callback_mask, CBM_INDT_ACCEPT_CARGO)) {
404 uint16 res = GetIndustryTileCallback(CBID_INDTILE_ACCEPT_CARGO, 0, 0, gfx, Industry::GetByTile(tile), tile);
405 if (res != CALLBACK_FAILED) {
406 accepts_cargo = raw_accepts_cargo;
407 for (uint i = 0; i < lengthof(itspec->accepts_cargo); i++) raw_accepts_cargo[i] = GetCargoTranslation(GB(res, i * 5, 5), itspec->grf_prop.grffile);
411 if (HasBit(itspec->callback_mask, CBM_INDT_CARGO_ACCEPTANCE)) {
412 uint16 res = GetIndustryTileCallback(CBID_INDTILE_CARGO_ACCEPTANCE, 0, 0, gfx, Industry::GetByTile(tile), tile);
413 if (res != CALLBACK_FAILED) {
414 cargo_acceptance = raw_cargo_acceptance;
415 for (uint i = 0; i < lengthof(itspec->accepts_cargo); i++) raw_cargo_acceptance[i] = GB(res, i * 4, 4);
419 const Industry *ind = Industry::GetByTile(tile);
420 for (byte i = 0; i < lengthof(itspec->accepts_cargo); i++) {
421 CargoID a = accepts_cargo[i];
422 if (a == CT_INVALID || cargo_acceptance[i] == 0) continue; // work only with valid cargoes
424 /* Add accepted cargo */
425 acceptance[a] += cargo_acceptance[i];
427 /* Maybe set 'always accepted' bit (if it's not set already) */
428 if (HasBit(*always_accepted, a)) continue;
430 bool accepts = false;
431 for (uint cargo_index = 0; cargo_index < lengthof(ind->accepts_cargo); cargo_index++) {
432 /* Test whether the industry itself accepts the cargo type */
433 if (ind->accepts_cargo[cargo_index] == a) {
434 accepts = true;
435 break;
439 if (accepts) continue;
441 /* If the industry itself doesn't accept this cargo, set 'always accepted' bit */
442 SetBit(*always_accepted, a);
446 static void GetTileDesc_Industry(TileIndex tile, TileDesc *td)
448 const Industry *i = Industry::GetByTile(tile);
449 const IndustrySpec *is = GetIndustrySpec(i->type);
451 td->owner[0] = i->owner;
452 td->str = is->name;
453 if (!IsIndustryCompleted(tile)) {
454 SetDParamX(td->dparam, 0, td->str);
455 td->str = STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION;
458 if (is->grf_prop.grffile != NULL) {
459 td->grf = GetGRFConfig(is->grf_prop.grffile->grfid)->GetName();
463 static CommandCost ClearTile_Industry(TileIndex tile, DoCommandFlag flags)
465 Industry *i = Industry::GetByTile(tile);
466 const IndustrySpec *indspec = GetIndustrySpec(i->type);
468 /* water can destroy industries
469 * in editor you can bulldoze industries
470 * with magic_bulldozer cheat you can destroy industries
471 * (area around OILRIG is water, so water shouldn't flood it
473 if ((_current_company != OWNER_WATER && _game_mode != GM_EDITOR &&
474 !_cheats.magic_bulldozer.value) ||
475 ((flags & DC_AUTO) != 0) ||
476 (_current_company == OWNER_WATER &&
477 ((indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) ||
478 HasBit(GetIndustryTileSpec(GetIndustryGfx(tile))->slopes_refused, 5)))) {
479 SetDParam(1, indspec->name);
480 return_cmd_error(flags & DC_AUTO ? STR_ERROR_GENERIC_OBJECT_IN_THE_WAY : INVALID_STRING_ID);
483 if (flags & DC_EXEC) {
484 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index));
485 Game::NewEvent(new ScriptEventIndustryClose(i->index));
486 delete i;
488 return CommandCost(EXPENSES_CONSTRUCTION, indspec->GetRemovalCost());
491 static void TransportIndustryGoods(TileIndex tile)
493 Industry *i = Industry::GetByTile(tile);
494 const IndustrySpec *indspec = GetIndustrySpec(i->type);
495 bool moved_cargo = false;
497 StationFinder stations(i->location);
499 for (uint j = 0; j < lengthof(i->produced_cargo_waiting); j++) {
500 uint cw = min(i->produced_cargo_waiting[j], 255);
501 if (cw > indspec->minimal_cargo && i->produced_cargo[j] != CT_INVALID) {
502 i->produced_cargo_waiting[j] -= cw;
504 /* fluctuating economy? */
505 if (EconomyIsInRecession()) cw = (cw + 1) / 2;
507 i->this_month_production[j] += cw;
509 uint am = MoveGoodsToStation(i->produced_cargo[j], cw, ST_INDUSTRY, i->index, stations.GetStations());
510 i->this_month_transported[j] += am;
512 moved_cargo |= (am != 0);
516 if (moved_cargo && !StartStopIndustryTileAnimation(i, IAT_INDUSTRY_DISTRIBUTES_CARGO)) {
517 uint newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_production;
519 if (newgfx != INDUSTRYTILE_NOANIM) {
520 ResetIndustryConstructionStage(tile);
521 SetIndustryCompleted(tile, true);
522 SetIndustryGfx(tile, newgfx);
523 MarkTileDirtyByTile(tile);
529 static void AnimateTile_Industry(TileIndex tile)
531 IndustryGfx gfx = GetIndustryGfx(tile);
533 if (GetIndustryTileSpec(gfx)->animation.status != ANIM_STATUS_NO_ANIMATION) {
534 AnimateNewIndustryTile(tile);
535 return;
538 switch (gfx) {
539 case GFX_SUGAR_MINE_SIEVE:
540 if ((_tick_counter & 1) == 0) {
541 byte m = GetAnimationFrame(tile) + 1;
543 if (_settings_client.sound.ambient) {
544 switch (m & 7) {
545 case 2: SndPlayTileFx(SND_2D_RIP_2, tile); break;
546 case 6: SndPlayTileFx(SND_29_RIP, tile); break;
550 if (m >= 96) {
551 m = 0;
552 DeleteAnimatedTile(tile);
554 SetAnimationFrame(tile, m);
556 MarkTileDirtyByTile(tile);
558 break;
560 case GFX_TOFFEE_QUARY:
561 if ((_tick_counter & 3) == 0) {
562 byte m = GetAnimationFrame(tile);
564 if (_industry_anim_offs_toffee[m] == 0xFF && _settings_client.sound.ambient) {
565 SndPlayTileFx(SND_30_CARTOON_SOUND, tile);
568 if (++m >= 70) {
569 m = 0;
570 DeleteAnimatedTile(tile);
572 SetAnimationFrame(tile, m);
574 MarkTileDirtyByTile(tile);
576 break;
578 case GFX_BUBBLE_CATCHER:
579 if ((_tick_counter & 1) == 0) {
580 byte m = GetAnimationFrame(tile);
582 if (++m >= 40) {
583 m = 0;
584 DeleteAnimatedTile(tile);
586 SetAnimationFrame(tile, m);
588 MarkTileDirtyByTile(tile);
590 break;
592 /* Sparks on a coal plant */
593 case GFX_POWERPLANT_SPARKS:
594 if ((_tick_counter & 3) == 0) {
595 byte m = GetAnimationFrame(tile);
596 if (m == 6) {
597 SetAnimationFrame(tile, 0);
598 DeleteAnimatedTile(tile);
599 } else {
600 SetAnimationFrame(tile, m + 1);
601 MarkTileDirtyByTile(tile);
604 break;
606 case GFX_TOY_FACTORY:
607 if ((_tick_counter & 1) == 0) {
608 byte m = GetAnimationFrame(tile) + 1;
610 switch (m) {
611 case 1: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2C_MACHINERY, tile); break;
612 case 23: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2B_COMEDY_HIT, tile); break;
613 case 28: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2A_EXTRACT_AND_POP, tile); break;
614 default:
615 if (m >= 50) {
616 int n = GetIndustryAnimationLoop(tile) + 1;
617 m = 0;
618 if (n >= 8) {
619 n = 0;
620 DeleteAnimatedTile(tile);
622 SetIndustryAnimationLoop(tile, n);
626 SetAnimationFrame(tile, m);
627 MarkTileDirtyByTile(tile);
629 break;
631 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
632 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
633 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
634 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
635 if ((_tick_counter & 3) == 0) {
636 IndustryGfx gfx = GetIndustryGfx(tile);
638 gfx = (gfx < 155) ? gfx + 1 : 148;
639 SetIndustryGfx(tile, gfx);
640 MarkTileDirtyByTile(tile);
642 break;
644 case GFX_OILWELL_ANIMATED_1:
645 case GFX_OILWELL_ANIMATED_2:
646 case GFX_OILWELL_ANIMATED_3:
647 if ((_tick_counter & 7) == 0) {
648 bool b = Chance16(1, 7);
649 IndustryGfx gfx = GetIndustryGfx(tile);
651 byte m = GetAnimationFrame(tile) + 1;
652 if (m == 4 && (m = 0, ++gfx) == GFX_OILWELL_ANIMATED_3 + 1 && (gfx = GFX_OILWELL_ANIMATED_1, b)) {
653 SetIndustryGfx(tile, GFX_OILWELL_NOT_ANIMATED);
654 SetIndustryConstructionStage(tile, 3);
655 DeleteAnimatedTile(tile);
656 } else {
657 SetAnimationFrame(tile, m);
658 SetIndustryGfx(tile, gfx);
659 MarkTileDirtyByTile(tile);
662 break;
664 case GFX_COAL_MINE_TOWER_ANIMATED:
665 case GFX_COPPER_MINE_TOWER_ANIMATED:
666 case GFX_GOLD_MINE_TOWER_ANIMATED: {
667 int state = _tick_counter & 0x7FF;
669 if ((state -= 0x400) < 0) return;
671 if (state < 0x1A0) {
672 if (state < 0x20 || state >= 0x180) {
673 byte m = GetAnimationFrame(tile);
674 if (!(m & 0x40)) {
675 SetAnimationFrame(tile, m | 0x40);
676 if (_settings_client.sound.ambient) SndPlayTileFx(SND_0B_MINING_MACHINERY, tile);
678 if (state & 7) return;
679 } else {
680 if (state & 3) return;
682 byte m = (GetAnimationFrame(tile) + 1) | 0x40;
683 if (m > 0xC2) m = 0xC0;
684 SetAnimationFrame(tile, m);
685 MarkTileDirtyByTile(tile);
686 } else if (state >= 0x200 && state < 0x3A0) {
687 int i = (state < 0x220 || state >= 0x380) ? 7 : 3;
688 if (state & i) return;
690 byte m = (GetAnimationFrame(tile) & 0xBF) - 1;
691 if (m < 0x80) m = 0x82;
692 SetAnimationFrame(tile, m);
693 MarkTileDirtyByTile(tile);
695 break;
700 static void CreateChimneySmoke(TileIndex tile)
702 uint x = TileX(tile) * TILE_SIZE;
703 uint y = TileY(tile) * TILE_SIZE;
704 int z = GetTileMaxPixelZ(tile);
706 CreateEffectVehicle(x + 15, y + 14, z + 59, EV_CHIMNEY_SMOKE);
709 static void MakeIndustryTileBigger(TileIndex tile)
711 byte cnt = GetIndustryConstructionCounter(tile) + 1;
712 if (cnt != 4) {
713 SetIndustryConstructionCounter(tile, cnt);
714 return;
717 byte stage = GetIndustryConstructionStage(tile) + 1;
718 SetIndustryConstructionCounter(tile, 0);
719 SetIndustryConstructionStage(tile, stage);
720 StartStopIndustryTileAnimation(tile, IAT_CONSTRUCTION_STATE_CHANGE);
721 if (stage == INDUSTRY_COMPLETED) SetIndustryCompleted(tile, true);
723 MarkTileDirtyByTile(tile);
725 if (!IsIndustryCompleted(tile)) return;
727 IndustryGfx gfx = GetIndustryGfx(tile);
728 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
729 /* New industries are already animated on construction. */
730 return;
733 switch (gfx) {
734 case GFX_POWERPLANT_CHIMNEY:
735 CreateChimneySmoke(tile);
736 break;
738 case GFX_OILRIG_1: {
739 /* Do not require an industry tile to be after the first two GFX_OILRIG_1
740 * tiles (like the default oil rig). Do a proper check to ensure the
741 * tiles belong to the same industry and based on that build the oil rig's
742 * station. */
743 TileIndex other = tile + TileDiffXY(0, 1);
745 if (IsIndustryTile(other) &&
746 GetIndustryGfx(other) == GFX_OILRIG_1 &&
747 GetIndustryIndex(tile) == GetIndustryIndex(other)) {
748 BuildOilRig(tile);
750 break;
753 case GFX_TOY_FACTORY:
754 case GFX_BUBBLE_CATCHER:
755 case GFX_TOFFEE_QUARY:
756 SetAnimationFrame(tile, 0);
757 SetIndustryAnimationLoop(tile, 0);
758 break;
760 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
761 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
762 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
763 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
764 AddAnimatedTile(tile);
765 break;
769 static void TileLoopIndustry_BubbleGenerator(TileIndex tile)
771 static const int8 _bubble_spawn_location[3][4] = {
772 { 11, 0, -4, -14 },
773 { -4, -10, -4, 1 },
774 { 49, 59, 60, 65 },
777 if (_settings_client.sound.ambient) SndPlayTileFx(SND_2E_EXTRACT_AND_POP, tile);
779 int dir = Random() & 3;
781 EffectVehicle *v = CreateEffectVehicleAbove(
782 TileX(tile) * TILE_SIZE + _bubble_spawn_location[0][dir],
783 TileY(tile) * TILE_SIZE + _bubble_spawn_location[1][dir],
784 _bubble_spawn_location[2][dir],
785 EV_BUBBLE
788 if (v != NULL) v->animation_substate = dir;
791 static void TileLoop_Industry(TileIndex tile)
793 if (IsTileOnWater(tile)) TileLoop_Water(tile);
795 /* Normally this doesn't happen, but if an industry NewGRF is removed
796 * an industry that was previously build on water can now be flooded.
797 * If this happens the tile is no longer an industry tile after
798 * returning from TileLoop_Water. */
799 if (!IsIndustryTile(tile)) return;
801 TriggerIndustryTile(tile, INDTILE_TRIGGER_TILE_LOOP);
803 if (!IsIndustryCompleted(tile)) {
804 MakeIndustryTileBigger(tile);
805 return;
808 if (_game_mode == GM_EDITOR) return;
810 TransportIndustryGoods(tile);
812 if (StartStopIndustryTileAnimation(tile, IAT_TILELOOP)) return;
814 IndustryGfx newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_next;
815 if (newgfx != INDUSTRYTILE_NOANIM) {
816 ResetIndustryConstructionStage(tile);
817 SetIndustryGfx(tile, newgfx);
818 MarkTileDirtyByTile(tile);
819 return;
822 IndustryGfx gfx = GetIndustryGfx(tile);
823 switch (gfx) {
824 case GFX_COAL_MINE_TOWER_NOT_ANIMATED:
825 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED:
826 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED:
827 if (!(_tick_counter & 0x400) && Chance16(1, 2)) {
828 switch (gfx) {
829 case GFX_COAL_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COAL_MINE_TOWER_ANIMATED; break;
830 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_ANIMATED; break;
831 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_ANIMATED; break;
833 SetIndustryGfx(tile, gfx);
834 SetAnimationFrame(tile, 0x80);
835 AddAnimatedTile(tile);
837 break;
839 case GFX_OILWELL_NOT_ANIMATED:
840 if (Chance16(1, 6)) {
841 SetIndustryGfx(tile, GFX_OILWELL_ANIMATED_1);
842 SetAnimationFrame(tile, 0);
843 AddAnimatedTile(tile);
845 break;
847 case GFX_COAL_MINE_TOWER_ANIMATED:
848 case GFX_COPPER_MINE_TOWER_ANIMATED:
849 case GFX_GOLD_MINE_TOWER_ANIMATED:
850 if (!(_tick_counter & 0x400)) {
851 switch (gfx) {
852 case GFX_COAL_MINE_TOWER_ANIMATED: gfx = GFX_COAL_MINE_TOWER_NOT_ANIMATED; break;
853 case GFX_COPPER_MINE_TOWER_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_NOT_ANIMATED; break;
854 case GFX_GOLD_MINE_TOWER_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_NOT_ANIMATED; break;
856 SetIndustryGfx(tile, gfx);
857 SetIndustryCompleted(tile, true);
858 SetIndustryConstructionStage(tile, 3);
859 DeleteAnimatedTile(tile);
861 break;
863 case GFX_POWERPLANT_SPARKS:
864 if (Chance16(1, 3)) {
865 if (_settings_client.sound.ambient) SndPlayTileFx(SND_0C_ELECTRIC_SPARK, tile);
866 AddAnimatedTile(tile);
868 break;
870 case GFX_COPPER_MINE_CHIMNEY:
871 CreateEffectVehicleAbove(TileX(tile) * TILE_SIZE + 6, TileY(tile) * TILE_SIZE + 6, 43, EV_COPPER_MINE_SMOKE);
872 break;
875 case GFX_TOY_FACTORY: {
876 Industry *i = Industry::GetByTile(tile);
877 if (i->was_cargo_delivered) {
878 i->was_cargo_delivered = false;
879 SetIndustryAnimationLoop(tile, 0);
880 AddAnimatedTile(tile);
883 break;
885 case GFX_BUBBLE_GENERATOR:
886 TileLoopIndustry_BubbleGenerator(tile);
887 break;
889 case GFX_TOFFEE_QUARY:
890 AddAnimatedTile(tile);
891 break;
893 case GFX_SUGAR_MINE_SIEVE:
894 if (Chance16(1, 3)) AddAnimatedTile(tile);
895 break;
899 static bool ClickTile_Industry(TileIndex tile)
901 ShowIndustryViewWindow(GetIndustryIndex(tile));
902 return true;
905 static void ChangeTileOwner_Industry(TileIndex tile, Owner old_owner, Owner new_owner)
907 /* If the founder merges, the industry was created by the merged company */
908 Industry *i = Industry::GetByTile(tile);
909 if (i->founder == old_owner) i->founder = (new_owner == INVALID_OWNER) ? OWNER_NONE : new_owner;
913 * Check whether the tile is a forest.
914 * @param tile the tile to investigate.
915 * @return true if and only if the tile is a forest
917 bool IsTileForestIndustry(TileIndex tile)
919 /* Check for industry tile */
920 if (!IsIndustryTile(tile)) return false;
922 const Industry *ind = Industry::GetByTile(tile);
924 /* Check for organic industry (i.e. not processing or extractive) */
925 if ((GetIndustrySpec(ind->type)->life_type & INDUSTRYLIFE_ORGANIC) == 0) return false;
927 /* Check for wood production */
928 for (uint i = 0; i < lengthof(ind->produced_cargo); i++) {
929 /* The industry produces wood. */
930 if (ind->produced_cargo[i] != CT_INVALID && CargoSpec::Get(ind->produced_cargo[i])->label == 'WOOD') return true;
933 return false;
936 static const byte _plantfarmfield_type[] = {1, 1, 1, 1, 1, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6};
938 static bool IsValidFarmFieldTile(TileIndex tile, bool allow_fields)
940 if (!IsGroundTile(tile)) return false;
942 return IsFieldsTile(tile) ? allow_fields :
943 !IsSnowTile(tile) && !IsClearGround(tile, GROUND_DESERT) && !IsClearGround(tile, GROUND_SHORE);
946 static void SetupFarmFieldFence(TileIndex tile, int size, byte type, DiagDirection side)
948 TileIndexDiff diff = (DiagDirToAxis(side) == AXIS_Y ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
950 do {
951 tile = TILE_MASK(tile);
953 if (IsFieldsTile(tile)) {
954 byte or_ = type;
956 if (or_ == 1 && Chance16(1, 7)) or_ = 2;
958 SetFence(tile, side, or_);
961 tile += diff;
962 } while (--size);
965 static void PlantFarmField(TileIndex tile, IndustryID industry)
967 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
968 if (GetTileZ(tile) + 2 >= GetSnowLine()) return;
971 /* determine field size */
972 uint32 r = (Random() & 0x303) + 0x404;
973 if (_settings_game.game_creation.landscape == LT_ARCTIC) r += 0x404;
974 uint size_x = GB(r, 0, 8);
975 uint size_y = GB(r, 8, 8);
977 TileArea ta(tile - TileDiffXY(min(TileX(tile), size_x / 2), min(TileY(tile), size_y / 2)), size_x, size_y);
978 ta.ClampToMap();
980 if (ta.w == 0 || ta.h == 0) return;
982 /* check the amount of bad tiles */
983 int count = 0;
984 TILE_AREA_LOOP(cur_tile, ta) {
985 assert(cur_tile < MapSize());
986 count += IsValidFarmFieldTile(cur_tile, false);
988 if (count * 2 < ta.w * ta.h) return;
990 /* determine type of field */
991 r = Random();
992 uint counter = GB(r, 5, 3);
993 uint field_type = GB(r, 8, 8) * 9 >> 8;
995 /* make field */
996 TILE_AREA_LOOP(cur_tile, ta) {
997 assert(cur_tile < MapSize());
998 if (IsValidFarmFieldTile(cur_tile, true)) {
999 MakeField(cur_tile, field_type, industry);
1000 SetClearCounter(cur_tile, counter);
1001 MarkTileDirtyByTile(cur_tile);
1005 int type = 3;
1006 if (_settings_game.game_creation.landscape != LT_ARCTIC && _settings_game.game_creation.landscape != LT_TROPIC) {
1007 type = _plantfarmfield_type[Random() & 0xF];
1010 SetupFarmFieldFence(ta.tile, ta.h, type, DIAGDIR_NE);
1011 SetupFarmFieldFence(ta.tile, ta.w, type, DIAGDIR_NW);
1012 SetupFarmFieldFence(ta.tile + TileDiffXY(ta.w - 1, 0), ta.h, type, DIAGDIR_SW);
1013 SetupFarmFieldFence(ta.tile + TileDiffXY(0, ta.h - 1), ta.w, type, DIAGDIR_SE);
1016 void PlantRandomFarmField(const Industry *i)
1018 int x = i->location.w / 2 + Random() % 31 - 16;
1019 int y = i->location.h / 2 + Random() % 31 - 16;
1021 TileIndex tile = TileAddWrap(i->location.tile, x, y);
1023 if (tile != INVALID_TILE) PlantFarmField(tile, i->index);
1027 * Search callback function for ChopLumberMillTrees
1028 * @param tile to test
1029 * @param user_data that is passed by the caller. In this case, nothing
1030 * @return the result of the test
1032 static bool SearchLumberMillTrees(TileIndex tile, void *user_data)
1034 if (IsTreeTile(tile) && GetTreeGrowth(tile) > 2) { ///< 3 and up means all fully grown trees
1035 /* found a tree */
1037 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
1039 _industry_sound_ctr = 1;
1040 _industry_sound_tile = tile;
1041 if (_settings_client.sound.ambient) SndPlayTileFx(SND_38_CHAINSAW, tile);
1043 DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
1045 cur_company.Restore();
1046 return true;
1048 return false;
1052 * Perform a circular search around the Lumber Mill in order to find trees to cut
1053 * @param i industry
1055 static void ChopLumberMillTrees(Industry *i)
1057 /* We only want to cut trees if all tiles are completed. */
1058 TILE_AREA_LOOP(tile_cur, i->location) {
1059 if (i->TileBelongsToIndustry(tile_cur)) {
1060 if (!IsIndustryCompleted(tile_cur)) return;
1064 TileIndex tile = i->location.tile;
1065 if (CircularTileSearch(&tile, 40, SearchLumberMillTrees, NULL)) { // 40x40 tiles to search.
1066 i->produced_cargo_waiting[0] = min(0xffff, i->produced_cargo_waiting[0] + 45); // Found a tree, add according value to waiting cargo.
1070 static void ProduceIndustryGoods(Industry *i)
1072 const IndustrySpec *indsp = GetIndustrySpec(i->type);
1074 /* play a sound? */
1075 if ((i->counter & 0x3F) == 0) {
1076 uint32 r;
1077 uint num;
1078 if (Chance16R(1, 14, r) && (num = indsp->number_of_sounds) != 0 && _settings_client.sound.ambient) {
1079 SndPlayTileFx(
1080 (SoundFx)(indsp->random_sounds[((r >> 16) * num) >> 16]),
1081 i->location.tile);
1085 i->counter--;
1087 /* produce some cargo */
1088 if ((i->counter % INDUSTRY_PRODUCE_TICKS) == 0) {
1089 if (HasBit(indsp->callback_mask, CBM_IND_PRODUCTION_256_TICKS)) IndustryProductionCallback(i, 1);
1091 IndustryBehaviour indbehav = indsp->behaviour;
1092 i->produced_cargo_waiting[0] = min(0xffff, i->produced_cargo_waiting[0] + i->production_rate[0]);
1093 i->produced_cargo_waiting[1] = min(0xffff, i->produced_cargo_waiting[1] + i->production_rate[1]);
1095 if ((indbehav & INDUSTRYBEH_PLANT_FIELDS) != 0) {
1096 uint16 cb_res = CALLBACK_FAILED;
1097 if (HasBit(indsp->callback_mask, CBM_IND_SPECIAL_EFFECT)) {
1098 cb_res = GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 0, i, i->type, i->location.tile);
1101 bool plant;
1102 if (cb_res != CALLBACK_FAILED) {
1103 plant = ConvertBooleanCallback(indsp->grf_prop.grffile, CBID_INDUSTRY_SPECIAL_EFFECT, cb_res);
1104 } else {
1105 plant = Chance16(1, 8);
1108 if (plant) PlantRandomFarmField(i);
1110 if ((indbehav & INDUSTRYBEH_CUT_TREES) != 0) {
1111 uint16 cb_res = CALLBACK_FAILED;
1112 if (HasBit(indsp->callback_mask, CBM_IND_SPECIAL_EFFECT)) {
1113 cb_res = GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 1, i, i->type, i->location.tile);
1116 bool cut;
1117 if (cb_res != CALLBACK_FAILED) {
1118 cut = ConvertBooleanCallback(indsp->grf_prop.grffile, CBID_INDUSTRY_SPECIAL_EFFECT, cb_res);
1119 } else {
1120 cut = ((i->counter % INDUSTRY_CUT_TREE_TICKS) == 0);
1123 if (cut) ChopLumberMillTrees(i);
1126 TriggerIndustry(i, INDUSTRY_TRIGGER_INDUSTRY_TICK);
1127 StartStopIndustryTileAnimation(i, IAT_INDUSTRY_TICK);
1131 void OnTick_Industry()
1133 if (_industry_sound_ctr != 0) {
1134 _industry_sound_ctr++;
1136 if (_industry_sound_ctr == 75) {
1137 if (_settings_client.sound.ambient) SndPlayTileFx(SND_37_BALLOON_SQUEAK, _industry_sound_tile);
1138 } else if (_industry_sound_ctr == 160) {
1139 _industry_sound_ctr = 0;
1140 if (_settings_client.sound.ambient) SndPlayTileFx(SND_36_CARTOON_CRASH, _industry_sound_tile);
1144 if (_game_mode == GM_EDITOR) return;
1146 Industry *i;
1147 FOR_ALL_INDUSTRIES(i) {
1148 ProduceIndustryGoods(i);
1153 * Check the conditions of #CHECK_NOTHING (Always succeeds).
1154 * @param tile %Tile to perform the checking.
1155 * @return Succeeded or failed command.
1157 static CommandCost CheckNewIndustry_NULL(TileIndex tile)
1159 return CommandCost();
1163 * Check the conditions of #CHECK_FOREST (Industry should be build above snow-line in arctic climate).
1164 * @param tile %Tile to perform the checking.
1165 * @return Succeeded or failed command.
1167 static CommandCost CheckNewIndustry_Forest(TileIndex tile)
1169 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
1170 if (GetTileZ(tile) < HighestSnowLine() + 2) {
1171 return_cmd_error(STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED);
1174 return CommandCost();
1178 * Check the conditions of #CHECK_REFINERY (Industry should be positioned near edge of the map).
1179 * @param tile %Tile to perform the checking.
1180 * @return Succeeded or failed command.
1182 static CommandCost CheckNewIndustry_OilRefinery(TileIndex tile)
1184 if (_game_mode == GM_EDITOR) return CommandCost();
1185 if (DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _settings_game.game_creation.oil_refinery_limit) return CommandCost();
1187 return_cmd_error(STR_ERROR_CAN_ONLY_BE_POSITIONED);
1190 extern bool _ignore_restrictions;
1193 * Check the conditions of #CHECK_OIL_RIG (Industries at sea should be positioned near edge of the map).
1194 * @param tile %Tile to perform the checking.
1195 * @return Succeeded or failed command.
1197 static CommandCost CheckNewIndustry_OilRig(TileIndex tile)
1199 if (_game_mode == GM_EDITOR && _ignore_restrictions) return CommandCost();
1200 if (TileHeight(tile) == 0 &&
1201 DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _settings_game.game_creation.oil_refinery_limit) return CommandCost();
1203 return_cmd_error(STR_ERROR_CAN_ONLY_BE_POSITIONED);
1207 * Check the conditions of #CHECK_FARM (Industry should be below snow-line in arctic).
1208 * @param tile %Tile to perform the checking.
1209 * @return Succeeded or failed command.
1211 static CommandCost CheckNewIndustry_Farm(TileIndex tile)
1213 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
1214 if (GetTileZ(tile) + 2 >= HighestSnowLine()) {
1215 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1218 return CommandCost();
1222 * Check the conditions of #CHECK_PLANTATION (Industry should NOT be in the desert).
1223 * @param tile %Tile to perform the checking.
1224 * @return Succeeded or failed command.
1226 static CommandCost CheckNewIndustry_Plantation(TileIndex tile)
1228 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
1229 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1231 return CommandCost();
1235 * Check the conditions of #CHECK_WATER (Industry should be in the desert).
1236 * @param tile %Tile to perform the checking.
1237 * @return Succeeded or failed command.
1239 static CommandCost CheckNewIndustry_Water(TileIndex tile)
1241 if (GetTropicZone(tile) != TROPICZONE_DESERT) {
1242 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT);
1244 return CommandCost();
1248 * Check the conditions of #CHECK_LUMBERMILL (Industry should be in the rain forest).
1249 * @param tile %Tile to perform the checking.
1250 * @return Succeeded or failed command.
1252 static CommandCost CheckNewIndustry_Lumbermill(TileIndex tile)
1254 if (GetTropicZone(tile) != TROPICZONE_RAINFOREST) {
1255 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST);
1257 return CommandCost();
1261 * Check the conditions of #CHECK_BUBBLEGEN (Industry should be in low land).
1262 * @param tile %Tile to perform the checking.
1263 * @return Succeeded or failed command.
1265 static CommandCost CheckNewIndustry_BubbleGen(TileIndex tile)
1267 if (GetTileZ(tile) > 4) {
1268 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS);
1270 return CommandCost();
1274 * Industrytype check function signature.
1275 * @param tile %Tile to check.
1276 * @return Succeeded or failed command.
1278 typedef CommandCost CheckNewIndustryProc(TileIndex tile);
1280 /** Check functions for different types of industry. */
1281 static CheckNewIndustryProc * const _check_new_industry_procs[CHECK_END] = {
1282 CheckNewIndustry_NULL, ///< CHECK_NOTHING
1283 CheckNewIndustry_Forest, ///< CHECK_FOREST
1284 CheckNewIndustry_OilRefinery, ///< CHECK_REFINERY
1285 CheckNewIndustry_Farm, ///< CHECK_FARM
1286 CheckNewIndustry_Plantation, ///< CHECK_PLANTATION
1287 CheckNewIndustry_Water, ///< CHECK_WATER
1288 CheckNewIndustry_Lumbermill, ///< CHECK_LUMBERMILL
1289 CheckNewIndustry_BubbleGen, ///< CHECK_BUBBLEGEN
1290 CheckNewIndustry_OilRig, ///< CHECK_OIL_RIG
1294 * Find a town for the industry, while checking for multiple industries in the same town.
1295 * @param tile Position of the industry to build.
1296 * @param type Industry type.
1297 * @param [out] town Pointer to return town for the new industry, \c NULL is written if no good town can be found.
1298 * @return Succeeded or failed command.
1300 * @pre \c *t != NULL
1301 * @post \c *t points to a town on success, and \c NULL on failure.
1303 static CommandCost FindTownForIndustry(TileIndex tile, int type, Town **t)
1305 *t = ClosestTownFromTile(tile, UINT_MAX);
1307 if (_settings_game.economy.multiple_industry_per_town) return CommandCost();
1309 const Industry *i;
1310 FOR_ALL_INDUSTRIES(i) {
1311 if (i->type == (byte)type && i->town == *t) {
1312 *t = NULL;
1313 return_cmd_error(STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN);
1317 return CommandCost();
1320 bool IsSlopeRefused(Slope current, Slope refused)
1322 if (IsSteepSlope(current)) return true;
1323 if (current != SLOPE_FLAT) {
1324 if (IsSteepSlope(refused)) return true;
1326 Slope t = ComplementSlope(current);
1328 if ((refused & SLOPE_W) && (t & SLOPE_NW)) return true;
1329 if ((refused & SLOPE_S) && (t & SLOPE_NE)) return true;
1330 if ((refused & SLOPE_E) && (t & SLOPE_SW)) return true;
1331 if ((refused & SLOPE_N) && (t & SLOPE_SE)) return true;
1334 return false;
1338 * Are the tiles of the industry free?
1339 * @param tile Position to check.
1340 * @param it Industry tiles table.
1341 * @param itspec_index The index of the itsepc to build/fund
1342 * @param type Type of the industry.
1343 * @param initial_random_bits The random bits the industry is going to have after construction.
1344 * @param founder Industry founder
1345 * @param creation_type The circumstances the industry is created under.
1346 * @param [out] custom_shape_check Perform custom check for the site.
1347 * @return Failed or succeeded command.
1349 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)
1351 bool refused_slope = false;
1352 bool custom_shape = false;
1354 do {
1355 IndustryGfx gfx = GetTranslatedIndustryTileID(it->gfx);
1356 TileIndex cur_tile = TileAddWrap(tile, it->ti.x, it->ti.y);
1358 if (!IsValidTile(cur_tile)) {
1359 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1362 if (gfx == GFX_WATERTILE_SPECIALCHECK) {
1363 if (!IsWaterTile(cur_tile) ||
1364 !IsTileFlat(cur_tile)) {
1365 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1367 } else {
1368 CommandCost ret = EnsureNoVehicleOnGround(cur_tile);
1369 if (ret.Failed()) return ret;
1370 if (HasBridgeAbove(cur_tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1372 const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
1374 IndustryBehaviour ind_behav = GetIndustrySpec(type)->behaviour;
1376 /* Perform land/water check if not disabled */
1377 if (!HasBit(its->slopes_refused, 5) && ((HasTileWaterClass(cur_tile) && IsTileOnWater(cur_tile)) == !(ind_behav & INDUSTRYBEH_BUILT_ONWATER))) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1379 if (HasBit(its->callback_mask, CBM_INDT_SHAPE_CHECK)) {
1380 custom_shape = true;
1381 CommandCost ret = PerformIndustryTileSlopeCheck(tile, cur_tile, its, type, gfx, itspec_index, initial_random_bits, founder, creation_type);
1382 if (ret.Failed()) return ret;
1383 } else {
1384 Slope tileh = GetTileSlope(cur_tile);
1385 refused_slope |= IsSlopeRefused(tileh, its->slopes_refused);
1388 if ((ind_behav & (INDUSTRYBEH_ONLY_INTOWN | INDUSTRYBEH_TOWN1200_MORE)) || // Tile must be a house
1389 ((ind_behav & INDUSTRYBEH_ONLY_NEARTOWN) && IsHouseTile(cur_tile))) { // Tile is allowed to be a house (and it is a house)
1390 if (!IsHouseTile(cur_tile)) {
1391 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS);
1394 /* Clear the tiles as OWNER_TOWN to not affect town rating, and to not clear protected buildings */
1395 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
1396 CommandCost ret = DoCommand(cur_tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR);
1397 cur_company.Restore();
1399 if (ret.Failed()) return ret;
1400 } else {
1401 /* Clear the tiles, but do not affect town ratings */
1402 CommandCost ret = DoCommand(cur_tile, 0, 0, DC_AUTO | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR);
1404 if (ret.Failed()) return ret;
1407 } while ((++it)->ti.x != -0x80);
1409 if (custom_shape_check != NULL) *custom_shape_check = custom_shape;
1411 /* It is almost impossible to have a fully flat land in TG, so what we
1412 * do is that we check if we can make the land flat later on. See
1413 * CheckIfCanLevelIndustryPlatform(). */
1414 if (!refused_slope || (_settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world && !custom_shape && !_ignore_restrictions)) {
1415 return CommandCost();
1417 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1421 * Is the industry allowed to be built at this place for the town?
1422 * @param tile Tile to construct the industry.
1423 * @param type Type of the industry.
1424 * @param t Town authority that the industry belongs to.
1425 * @return Succeeded or failed command.
1427 static CommandCost CheckIfIndustryIsAllowed(TileIndex tile, int type, const Town *t)
1429 if ((GetIndustrySpec(type)->behaviour & INDUSTRYBEH_TOWN1200_MORE) && t->cache.population < 1200) {
1430 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200);
1433 if ((GetIndustrySpec(type)->behaviour & INDUSTRYBEH_ONLY_NEARTOWN) && DistanceMax(t->xy, tile) > 9) {
1434 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER);
1437 return CommandCost();
1440 static bool CheckCanTerraformSurroundingTiles(TileIndex tile, uint height, int internal)
1442 /* Check if we don't leave the map */
1443 if (TileX(tile) == 0 || TileY(tile) == 0 || IsVoidTile(tile)) return false;
1445 TileArea ta(tile - TileDiffXY(1, 1), 2, 2);
1446 TILE_AREA_LOOP(tile_walk, ta) {
1447 uint curh = TileHeight(tile_walk);
1448 /* Is the tile clear? */
1449 if (!IsGroundTile(tile_walk)) return false;
1451 /* Don't allow too big of a change if this is the sub-tile check */
1452 if (internal != 0 && Delta(curh, height) > 1) return false;
1454 /* Different height, so the surrounding tiles of this tile
1455 * has to be correct too (in level, or almost in level)
1456 * else you get a chain-reaction of terraforming. */
1457 if (internal == 0 && curh != height) {
1458 if (TileX(tile_walk) == 0 || TileY(tile_walk) == 0 || !CheckCanTerraformSurroundingTiles(tile_walk + TileDiffXY(-1, -1), height, internal + 1)) {
1459 return false;
1464 return true;
1468 * This function tries to flatten out the land below an industry, without
1469 * damaging the surroundings too much.
1471 static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, DoCommandFlag flags, const IndustryTileTable *it, int type)
1473 const int MKEND = -0x80; // used for last element in an IndustryTileTable (see build_industry.h)
1474 int max_x = 0;
1475 int max_y = 0;
1477 /* Finds dimensions of largest variant of this industry */
1478 do {
1479 if (it->gfx == 0xFF) continue; // FF been a marquer for a check on clear water, skip it
1480 if (it->ti.x > max_x) max_x = it->ti.x;
1481 if (it->ti.y > max_y) max_y = it->ti.y;
1482 } while ((++it)->ti.x != MKEND);
1484 /* Remember level height */
1485 uint h = TileHeight(tile);
1487 if (TileX(tile) <= _settings_game.construction.industry_platform + 1U || TileY(tile) <= _settings_game.construction.industry_platform + 1U) return false;
1488 /* Check that all tiles in area and surrounding are clear
1489 * this determines that there are no obstructing items */
1491 TileArea ta(tile + TileDiffXY(-_settings_game.construction.industry_platform, -_settings_game.construction.industry_platform),
1492 max_x + 2 + 2 * _settings_game.construction.industry_platform, max_y + 2 + 2 * _settings_game.construction.industry_platform);
1494 if (TileX(ta.tile) + ta.w >= MapMaxX() || TileY(ta.tile) + ta.h >= MapMaxY()) return false;
1496 /* _current_company is OWNER_NONE for randomly generated industries and in editor, or the company who funded or prospected the industry.
1497 * Perform terraforming as OWNER_TOWN to disable autoslope and town ratings. */
1498 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
1500 TILE_AREA_LOOP(tile_walk, ta) {
1501 uint curh = TileHeight(tile_walk);
1502 if (curh != h) {
1503 /* This tile needs terraforming. Check if we can do that without
1504 * damaging the surroundings too much. */
1505 if (!CheckCanTerraformSurroundingTiles(tile_walk, h, 0)) {
1506 cur_company.Restore();
1507 return false;
1509 /* This is not 100% correct check, but the best we can do without modifying the map.
1510 * What is missing, is if the difference in height is more than 1.. */
1511 if (DoCommand(tile_walk, SLOPE_N, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND).Failed()) {
1512 cur_company.Restore();
1513 return false;
1518 if (flags & DC_EXEC) {
1519 /* Terraform the land under the industry */
1520 TILE_AREA_LOOP(tile_walk, ta) {
1521 uint curh = TileHeight(tile_walk);
1522 while (curh != h) {
1523 /* We give the terraforming for free here, because we can't calculate
1524 * exact cost in the test-round, and as we all know, that will cause
1525 * a nice assert if they don't match ;) */
1526 DoCommand(tile_walk, SLOPE_N, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND);
1527 curh += (curh > h) ? -1 : 1;
1532 cur_company.Restore();
1533 return true;
1538 * Check that the new industry is far enough from conflicting industries.
1539 * @param tile Tile to construct the industry.
1540 * @param type Type of the new industry.
1541 * @return Succeeded or failed command.
1543 static CommandCost CheckIfFarEnoughFromConflictingIndustry(TileIndex tile, int type)
1545 const IndustrySpec *indspec = GetIndustrySpec(type);
1546 const Industry *i;
1547 FOR_ALL_INDUSTRIES(i) {
1548 /* Within 14 tiles from another industry is considered close */
1549 if (DistanceMax(tile, i->location.tile) > 14) continue;
1551 /* check if there are any conflicting industry types around */
1552 if (i->type == indspec->conflicting[0] ||
1553 i->type == indspec->conflicting[1] ||
1554 i->type == indspec->conflicting[2]) {
1555 return_cmd_error(STR_ERROR_INDUSTRY_TOO_CLOSE);
1558 return CommandCost();
1562 * Advertise about a new industry opening.
1563 * @param ind Industry being opened.
1565 static void AdvertiseIndustryOpening(const Industry *ind)
1567 const IndustrySpec *ind_spc = GetIndustrySpec(ind->type);
1568 SetDParam(0, ind_spc->name);
1569 if (ind_spc->new_industry_text > STR_LAST_STRINGID) {
1570 SetDParam(1, STR_TOWN_NAME);
1571 SetDParam(2, ind->town->index);
1572 } else {
1573 SetDParam(1, ind->town->index);
1575 AddIndustryNewsItem(ind_spc->new_industry_text, NT_INDUSTRY_OPEN, ind->index);
1576 AI::BroadcastNewEvent(new ScriptEventIndustryOpen(ind->index));
1577 Game::NewEvent(new ScriptEventIndustryOpen(ind->index));
1581 * Put an industry on the map.
1582 * @param i Just allocated poolitem, mostly empty.
1583 * @param tile North tile of the industry.
1584 * @param type Type of the industry.
1585 * @param it Industrylayout to build.
1586 * @param layout Number of the layout.
1587 * @param t Nearest town.
1588 * @param founder Founder of the industry; OWNER_NONE in case of random construction.
1589 * @param initial_random_bits Random bits for the industry.
1591 static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, const IndustryTileTable *it, byte layout, Town *t, Owner founder, uint16 initial_random_bits)
1593 const IndustrySpec *indspec = GetIndustrySpec(type);
1595 i->location = TileArea(tile, 1, 1);
1596 i->type = type;
1597 Industry::IncIndustryTypeCount(type);
1599 i->produced_cargo[0] = indspec->produced_cargo[0];
1600 i->produced_cargo[1] = indspec->produced_cargo[1];
1601 i->accepts_cargo[0] = indspec->accepts_cargo[0];
1602 i->accepts_cargo[1] = indspec->accepts_cargo[1];
1603 i->accepts_cargo[2] = indspec->accepts_cargo[2];
1604 i->production_rate[0] = indspec->production_rate[0];
1605 i->production_rate[1] = indspec->production_rate[1];
1607 /* don't use smooth economy for industries using production related callbacks */
1608 if (indspec->UsesSmoothEconomy()) {
1609 i->production_rate[0] = min((RandomRange(256) + 128) * i->production_rate[0] >> 8, 255);
1610 i->production_rate[1] = min((RandomRange(256) + 128) * i->production_rate[1] >> 8, 255);
1613 i->town = t;
1614 i->owner = OWNER_NONE;
1616 uint16 r = Random();
1617 i->random_colour = GB(r, 0, 4);
1618 i->counter = GB(r, 4, 12);
1619 i->random = initial_random_bits;
1620 i->produced_cargo_waiting[0] = 0;
1621 i->produced_cargo_waiting[1] = 0;
1622 i->incoming_cargo_waiting[0] = 0;
1623 i->incoming_cargo_waiting[1] = 0;
1624 i->incoming_cargo_waiting[2] = 0;
1625 i->this_month_production[0] = 0;
1626 i->this_month_production[1] = 0;
1627 i->this_month_transported[0] = 0;
1628 i->this_month_transported[1] = 0;
1629 i->last_month_pct_transported[0] = 0;
1630 i->last_month_pct_transported[1] = 0;
1631 i->last_month_transported[0] = 0;
1632 i->last_month_transported[1] = 0;
1633 i->was_cargo_delivered = false;
1634 i->last_prod_year = _cur_year;
1635 i->founder = founder;
1637 i->construction_date = _date;
1638 i->construction_type = (_game_mode == GM_EDITOR) ? ICT_SCENARIO_EDITOR :
1639 (_generating_world ? ICT_MAP_GENERATION : ICT_NORMAL_GAMEPLAY);
1641 /* Adding 1 here makes it conform to specs of var44 of varaction2 for industries
1642 * 0 = created prior of newindustries
1643 * else, chosen layout + 1 */
1644 i->selected_layout = layout + 1;
1646 i->prod_level = PRODLEVEL_DEFAULT;
1648 /* Call callbacks after the regular fields got initialised. */
1650 if (HasBit(indspec->callback_mask, CBM_IND_PROD_CHANGE_BUILD)) {
1651 uint16 res = GetIndustryCallback(CBID_INDUSTRY_PROD_CHANGE_BUILD, 0, Random(), i, type, INVALID_TILE);
1652 if (res != CALLBACK_FAILED) {
1653 if (res < PRODLEVEL_MINIMUM || res > PRODLEVEL_MAXIMUM) {
1654 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_PROD_CHANGE_BUILD, res);
1655 } else {
1656 i->prod_level = res;
1657 i->RecomputeProductionMultipliers();
1662 if (_generating_world) {
1663 i->last_month_production[0] = i->production_rate[0] * 8;
1664 i->last_month_production[1] = i->production_rate[1] * 8;
1665 } else {
1666 i->last_month_production[0] = i->last_month_production[1] = 0;
1669 if (HasBit(indspec->callback_mask, CBM_IND_DECIDE_COLOUR)) {
1670 uint16 res = GetIndustryCallback(CBID_INDUSTRY_DECIDE_COLOUR, 0, 0, i, type, INVALID_TILE);
1671 if (res != CALLBACK_FAILED) {
1672 if (GB(res, 4, 11) != 0) ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_DECIDE_COLOUR, res);
1673 i->random_colour = GB(res, 0, 4);
1677 if (HasBit(indspec->callback_mask, CBM_IND_INPUT_CARGO_TYPES)) {
1678 for (uint j = 0; j < lengthof(i->accepts_cargo); j++) i->accepts_cargo[j] = CT_INVALID;
1679 for (uint j = 0; j < lengthof(i->accepts_cargo); j++) {
1680 uint16 res = GetIndustryCallback(CBID_INDUSTRY_INPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE);
1681 if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
1682 if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
1683 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_INPUT_CARGO_TYPES, res);
1684 break;
1686 i->accepts_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
1690 if (HasBit(indspec->callback_mask, CBM_IND_OUTPUT_CARGO_TYPES)) {
1691 for (uint j = 0; j < lengthof(i->produced_cargo); j++) i->produced_cargo[j] = CT_INVALID;
1692 for (uint j = 0; j < lengthof(i->produced_cargo); j++) {
1693 uint16 res = GetIndustryCallback(CBID_INDUSTRY_OUTPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE);
1694 if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
1695 if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
1696 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_OUTPUT_CARGO_TYPES, res);
1697 break;
1699 i->produced_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
1703 /* Plant the tiles */
1705 do {
1706 TileIndex cur_tile = tile + ToTileIndexDiff(it->ti);
1708 if (it->gfx != GFX_WATERTILE_SPECIALCHECK) {
1709 i->location.Add(cur_tile);
1711 WaterClass wc = (IsPlainWaterTile(cur_tile) ? GetWaterClass(cur_tile) : WATER_CLASS_INVALID);
1713 DoCommand(cur_tile, 0, 0, DC_EXEC | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR);
1715 MakeIndustry(cur_tile, i->index, it->gfx, Random(), wc);
1717 if (_generating_world) {
1718 SetIndustryConstructionCounter(cur_tile, 3);
1719 SetIndustryConstructionStage(cur_tile, 2);
1722 /* it->gfx is stored in the map. But the translated ID cur_gfx is the interesting one */
1723 IndustryGfx cur_gfx = GetTranslatedIndustryTileID(it->gfx);
1724 const IndustryTileSpec *its = GetIndustryTileSpec(cur_gfx);
1725 if (its->animation.status != ANIM_STATUS_NO_ANIMATION) AddAnimatedTile(cur_tile);
1727 } while ((++it)->ti.x != -0x80);
1729 if (GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_PLANT_ON_BUILT) {
1730 for (uint j = 0; j != 50; j++) PlantRandomFarmField(i);
1732 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0);
1734 Station::RecomputeIndustriesNearForAll();
1738 * Helper function for Build/Fund an industry
1739 * @param tile tile where industry is built
1740 * @param type of industry to build
1741 * @param flags of operations to conduct
1742 * @param indspec pointer to industry specifications
1743 * @param itspec_index the index of the itsepc to build/fund
1744 * @param seed random seed (possibly) used by industries
1745 * @param initial_random_bits The random bits the industry is going to have after construction.
1746 * @param founder Founder of the industry
1747 * @param creation_type The circumstances the industry is created under.
1748 * @param [out] ip Pointer to store newly created industry.
1749 * @return Succeeded or failed command.
1751 * @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.
1753 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)
1755 assert(itspec_index < indspec->num_table);
1756 const IndustryTileTable *it = indspec->table[itspec_index];
1757 bool custom_shape_check = false;
1759 *ip = NULL;
1761 SmallVector<ClearedObjectArea, 1> object_areas(_cleared_object_areas);
1762 CommandCost ret = CheckIfIndustryTilesAreFree(tile, it, itspec_index, type, random_initial_bits, founder, creation_type, &custom_shape_check);
1763 _cleared_object_areas = object_areas;
1764 if (ret.Failed()) return ret;
1766 if (HasBit(GetIndustrySpec(type)->callback_mask, CBM_IND_LOCATION)) {
1767 ret = CheckIfCallBackAllowsCreation(tile, type, itspec_index, random_var8f, random_initial_bits, founder, creation_type);
1768 } else {
1769 ret = _check_new_industry_procs[indspec->check_proc](tile);
1771 if (ret.Failed()) return ret;
1773 if (!custom_shape_check && _settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world &&
1774 !_ignore_restrictions && !CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER, it, type)) {
1775 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1778 ret = CheckIfFarEnoughFromConflictingIndustry(tile, type);
1779 if (ret.Failed()) return ret;
1781 Town *t = NULL;
1782 ret = FindTownForIndustry(tile, type, &t);
1783 if (ret.Failed()) return ret;
1784 assert(t != NULL);
1786 ret = CheckIfIndustryIsAllowed(tile, type, t);
1787 if (ret.Failed()) return ret;
1789 if (!Industry::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_INDUSTRIES);
1791 if (flags & DC_EXEC) {
1792 *ip = new Industry(tile);
1793 if (!custom_shape_check) CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER | DC_EXEC, it, type);
1794 DoCreateNewIndustry(*ip, tile, type, it, itspec_index, t, founder, random_initial_bits);
1797 return CommandCost();
1801 * Build/Fund an industry
1802 * @param tile tile where industry is built
1803 * @param flags of operations to conduct
1804 * @param p1 various bitstuffed elements
1805 * - p1 = (bit 0 - 7) - industry type see build_industry.h and see industry.h
1806 * - p1 = (bit 8 - 15) - first layout to try
1807 * - p1 = (bit 16 ) - 0 = prospect, 1 = fund (only valid if current company is DEITY)
1808 * @param p2 seed to use for desyncfree randomisations
1809 * @param text unused
1810 * @return the cost of this operation or an error
1812 CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1814 IndustryType it = GB(p1, 0, 8);
1815 if (it >= NUM_INDUSTRYTYPES) return CMD_ERROR;
1817 const IndustrySpec *indspec = GetIndustrySpec(it);
1819 /* Check if the to-be built/founded industry is available for this climate. */
1820 if (!indspec->enabled || indspec->num_table == 0) return CMD_ERROR;
1822 /* If the setting for raw-material industries is not on, you cannot build raw-material industries.
1823 * Raw material industries are industries that do not accept cargo (at least for now) */
1824 if (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 0 && indspec->IsRawIndustry()) {
1825 return CMD_ERROR;
1828 if (_game_mode != GM_EDITOR && GetIndustryProbabilityCallback(it, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, 1) == 0) {
1829 return CMD_ERROR;
1832 Randomizer randomizer;
1833 randomizer.SetSeed(p2);
1834 uint16 random_initial_bits = GB(p2, 0, 16);
1835 uint32 random_var8f = randomizer.Next();
1836 int num_layouts = indspec->num_table;
1837 CommandCost ret = CommandCost(STR_ERROR_SITE_UNSUITABLE);
1838 const bool deity_prospect = _current_company == OWNER_DEITY && !HasBit(p1, 16);
1840 Industry *ind = NULL;
1841 if (deity_prospect || (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 2 && indspec->IsRawIndustry())) {
1842 if (flags & DC_EXEC) {
1843 /* Prospected industries are build as OWNER_TOWN to not e.g. be build on owned land of the founder */
1844 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
1845 /* Prospecting has a chance to fail, however we cannot guarantee that something can
1846 * be built on the map, so the chance gets lower when the map is fuller, but there
1847 * is nothing we can really do about that. */
1848 if (deity_prospect || Random() <= indspec->prospecting_chance) {
1849 for (int i = 0; i < 5000; i++) {
1850 /* We should not have more than one Random() in a function call
1851 * because parameter evaluation order is not guaranteed in the c++ standard
1853 tile = RandomTile();
1854 /* Start with a random layout */
1855 int layout = RandomRange(num_layouts);
1856 /* Check now each layout, starting with the random one */
1857 for (int j = 0; j < num_layouts; j++) {
1858 layout = (layout + 1) % num_layouts;
1859 ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, cur_company.GetOriginalValue(), _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_PROSPECTCREATION, &ind);
1860 if (ret.Succeeded()) break;
1862 if (ret.Succeeded()) break;
1865 cur_company.Restore();
1867 } else {
1868 int layout = GB(p1, 8, 8);
1869 if (layout >= num_layouts) return CMD_ERROR;
1871 /* Check subsequently each layout, starting with the given layout in p1 */
1872 for (int i = 0; i < num_layouts; i++) {
1873 layout = (layout + 1) % num_layouts;
1874 ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, _current_company, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, &ind);
1875 if (ret.Succeeded()) break;
1878 /* If it still failed, there's no suitable layout to build here, return the error */
1879 if (ret.Failed()) return ret;
1882 if ((flags & DC_EXEC) && ind != NULL && _game_mode != GM_EDITOR) {
1883 AdvertiseIndustryOpening(ind);
1886 return CommandCost(EXPENSES_OTHER, indspec->GetConstructionCost());
1891 * Create a new industry of random layout.
1892 * @param tile The location to build the industry.
1893 * @param type The industry type to build.
1894 * @param creation_type The circumstances the industry is created under.
1895 * @return the created industry or NULL if it failed.
1897 static Industry *CreateNewIndustry(TileIndex tile, IndustryType type, IndustryAvailabilityCallType creation_type)
1899 const IndustrySpec *indspec = GetIndustrySpec(type);
1901 uint32 seed = Random();
1902 uint32 seed2 = Random();
1903 Industry *i = NULL;
1904 CommandCost ret = CreateNewIndustryHelper(tile, type, DC_EXEC, indspec, RandomRange(indspec->num_table), seed, GB(seed2, 0, 16), OWNER_NONE, creation_type, &i);
1905 assert(i != NULL || ret.Failed());
1906 return i;
1910 * Compute the appearance probability for an industry during map creation.
1911 * @param it Industry type to compute.
1912 * @param [out] force_at_least_one Returns whether at least one instance should be forced on map creation.
1913 * @return Relative probability for the industry to appear.
1915 static uint32 GetScaledIndustryGenerationProbability(IndustryType it, bool *force_at_least_one)
1917 const IndustrySpec *ind_spc = GetIndustrySpec(it);
1918 uint32 chance = ind_spc->appear_creation[_settings_game.game_creation.landscape] * 16; // * 16 to increase precision
1919 if (!ind_spc->enabled || ind_spc->num_table == 0 ||
1920 (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == ID_FUND_ONLY) ||
1921 (chance = GetIndustryProbabilityCallback(it, IACT_MAPGENERATION, chance)) == 0) {
1922 *force_at_least_one = false;
1923 return 0;
1924 } else {
1925 /* We want industries appearing at coast to appear less often on bigger maps, as length of coast increases slower than map area.
1926 * For simplicity we scale in both cases, though scaling the probabilities of all industries has no effect. */
1927 chance = (ind_spc->check_proc == CHECK_REFINERY || ind_spc->check_proc == CHECK_OIL_RIG) ? ScaleByMapPerimeter(chance) : ScaleByMapSize(chance);
1929 *force_at_least_one = (chance > 0) && !(ind_spc->behaviour & INDUSTRYBEH_NOBUILT_MAPCREATION) && (_game_mode != GM_EDITOR);
1930 return chance;
1935 * Compute the probability for constructing a new industry during game play.
1936 * @param it Industry type to compute.
1937 * @param [out] min_number Minimal number of industries that should exist at the map.
1938 * @return Relative probability for the industry to appear.
1940 static uint16 GetIndustryGamePlayProbability(IndustryType it, byte *min_number)
1942 if (_settings_game.difficulty.industry_density == ID_FUND_ONLY) {
1943 *min_number = 0;
1944 return 0;
1947 const IndustrySpec *ind_spc = GetIndustrySpec(it);
1948 byte chance = ind_spc->appear_ingame[_settings_game.game_creation.landscape];
1949 if (!ind_spc->enabled || ind_spc->num_table == 0 ||
1950 ((ind_spc->behaviour & INDUSTRYBEH_BEFORE_1950) && _cur_year > 1950) ||
1951 ((ind_spc->behaviour & INDUSTRYBEH_AFTER_1960) && _cur_year < 1960) ||
1952 (chance = GetIndustryProbabilityCallback(it, IACT_RANDOMCREATION, chance)) == 0) {
1953 *min_number = 0;
1954 return 0;
1956 *min_number = (ind_spc->behaviour & INDUSTRYBEH_CANCLOSE_LASTINSTANCE) ? 1 : 0;
1957 return chance;
1961 * Get wanted number of industries on the map.
1962 * @return Wanted number of industries at the map.
1964 static uint GetNumberOfIndustries()
1966 /* Number of industries on a 256x256 map. */
1967 static const uint16 numof_industry_table[] = {
1968 0, // none
1969 0, // minimal
1970 10, // very low
1971 25, // low
1972 55, // normal
1973 80, // high
1976 assert(lengthof(numof_industry_table) == ID_END);
1977 uint difficulty = (_game_mode != GM_EDITOR) ? _settings_game.difficulty.industry_density : (uint)ID_VERY_LOW;
1978 return ScaleByMapSize(numof_industry_table[difficulty]);
1982 * Try to place the industry in the game.
1983 * Since there is no feedback why placement fails, there is no other option
1984 * than to try a few times before concluding it does not work.
1985 * @param type Industry type of the desired industry.
1986 * @param try_hard Try very hard to find a place. (Used to place at least one industry per type.)
1987 * @return Pointer to created industry, or \c NULL if creation failed.
1989 static Industry *PlaceIndustry(IndustryType type, IndustryAvailabilityCallType creation_type, bool try_hard)
1991 uint tries = try_hard ? 10000u : 2000u;
1992 for (; tries > 0; tries--) {
1993 Industry *ind = CreateNewIndustry(RandomTile(), type, creation_type);
1994 if (ind != NULL) return ind;
1996 return NULL;
2000 * Try to build a industry on the map.
2001 * @param type IndustryType of the desired industry
2002 * @param try_hard Try very hard to find a place. (Used to place at least one industry per type)
2004 static void PlaceInitialIndustry(IndustryType type, bool try_hard)
2006 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
2008 IncreaseGeneratingWorldProgress(GWP_INDUSTRY);
2009 PlaceIndustry(type, IACT_MAPGENERATION, try_hard);
2011 cur_company.Restore();
2015 * Get total number of industries existing in the game.
2016 * @return Number of industries currently in the game.
2018 static uint GetCurrentTotalNumberOfIndustries()
2020 int total = 0;
2021 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) total += Industry::GetIndustryTypeCount(it);
2022 return total;
2026 /** Reset the entry. */
2027 void IndustryTypeBuildData::Reset()
2029 this->probability = 0;
2030 this->min_number = 0;
2031 this->target_count = 0;
2032 this->max_wait = 1;
2033 this->wait_count = 0;
2036 /** Completely reset the industry build data. */
2037 void IndustryBuildData::Reset()
2039 this->wanted_inds = GetCurrentTotalNumberOfIndustries() << 16;
2041 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2042 this->builddata[it].Reset();
2046 /** Monthly update of industry build data. */
2047 void IndustryBuildData::MonthlyLoop()
2049 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.
2050 if (_settings_game.difficulty.industry_density == ID_FUND_ONLY) return; // 'no industries' setting.
2052 /* To prevent running out of unused industries for the player to connect,
2053 * add a fraction of new industries each month, but only if the manager can keep up. */
2054 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).
2055 if (GetCurrentTotalNumberOfIndustries() + max_behind >= (this->wanted_inds >> 16)) {
2056 this->wanted_inds += ScaleByMapSize(NEWINDS_PER_MONTH);
2061 * This function will create random industries during game creation.
2062 * It will scale the amount of industries by mapsize and difficulty level.
2064 void GenerateIndustries()
2066 if (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == ID_FUND_ONLY) return; // No industries in the game.
2068 uint32 industry_probs[NUM_INDUSTRYTYPES];
2069 bool force_at_least_one[NUM_INDUSTRYTYPES];
2070 uint32 total_prob = 0;
2071 uint num_forced = 0;
2073 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2074 industry_probs[it] = GetScaledIndustryGenerationProbability(it, force_at_least_one + it);
2075 total_prob += industry_probs[it];
2076 if (force_at_least_one[it]) num_forced++;
2079 uint total_amount = GetNumberOfIndustries();
2080 if (total_prob == 0 || total_amount < num_forced) {
2081 /* Only place the forced ones */
2082 total_amount = num_forced;
2085 SetGeneratingWorldProgress(GWP_INDUSTRY, total_amount);
2087 /* Try to build one industry per type independent of any probabilities */
2088 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2089 if (force_at_least_one[it]) {
2090 assert(total_amount > 0);
2091 total_amount--;
2092 PlaceInitialIndustry(it, true);
2096 /* Add the remaining industries according to their probabilities */
2097 for (uint i = 0; i < total_amount; i++) {
2098 uint32 r = RandomRange(total_prob);
2099 IndustryType it = 0;
2100 while (r >= industry_probs[it]) {
2101 r -= industry_probs[it];
2102 it++;
2103 assert(it < NUM_INDUSTRYTYPES);
2105 assert(industry_probs[it] > 0);
2106 PlaceInitialIndustry(it, false);
2108 _industry_builder.Reset();
2112 * Monthly update of industry statistics.
2113 * @param i Industry to update.
2115 static void UpdateIndustryStatistics(Industry *i)
2117 for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
2118 if (i->produced_cargo[j] != CT_INVALID) {
2119 byte pct = 0;
2120 if (i->this_month_production[j] != 0) {
2121 i->last_prod_year = _cur_year;
2122 pct = min(i->this_month_transported[j] * 256 / i->this_month_production[j], 255);
2124 i->last_month_pct_transported[j] = pct;
2126 i->last_month_production[j] = i->this_month_production[j];
2127 i->this_month_production[j] = 0;
2129 i->last_month_transported[j] = i->this_month_transported[j];
2130 i->this_month_transported[j] = 0;
2136 * Recompute #production_rate for current #prod_level.
2137 * This function is only valid when not using smooth economy.
2139 void Industry::RecomputeProductionMultipliers()
2141 const IndustrySpec *indspec = GetIndustrySpec(this->type);
2142 assert(!indspec->UsesSmoothEconomy());
2144 /* Rates are rounded up, so e.g. oilrig always produces some passengers */
2145 this->production_rate[0] = min(CeilDiv(indspec->production_rate[0] * this->prod_level, PRODLEVEL_DEFAULT), 0xFF);
2146 this->production_rate[1] = min(CeilDiv(indspec->production_rate[1] * this->prod_level, PRODLEVEL_DEFAULT), 0xFF);
2151 * Set the #probability and #min_number fields for the industry type \a it for a running game.
2152 * @param it Industry type.
2153 * @return At least one of the fields has changed value.
2155 bool IndustryTypeBuildData::GetIndustryTypeData(IndustryType it)
2157 byte min_number;
2158 uint32 probability = GetIndustryGamePlayProbability(it, &min_number);
2159 bool changed = min_number != this->min_number || probability != this->probability;
2160 this->min_number = min_number;
2161 this->probability = probability;
2162 return changed;
2165 /** Decide how many industries of each type are needed. */
2166 void IndustryBuildData::SetupTargetCount()
2168 bool changed = false;
2169 uint num_planned = 0; // Number of industries planned in the industry build data.
2170 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2171 changed |= this->builddata[it].GetIndustryTypeData(it);
2172 num_planned += this->builddata[it].target_count;
2174 uint total_amount = this->wanted_inds >> 16; // Desired total number of industries.
2175 changed |= num_planned != total_amount;
2176 if (!changed) return; // All industries are still the same, no need to re-randomize.
2178 /* Initialize the target counts. */
2179 uint force_build = 0; // Number of industries that should always be available.
2180 uint32 total_prob = 0; // Sum of probabilities.
2181 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2182 IndustryTypeBuildData *ibd = this->builddata + it;
2183 force_build += ibd->min_number;
2184 ibd->target_count = ibd->min_number;
2185 total_prob += ibd->probability;
2188 if (total_prob == 0) return; // No buildable industries.
2190 /* Subtract forced industries from the number of industries available for construction. */
2191 total_amount = (total_amount <= force_build) ? 0 : total_amount - force_build;
2193 /* Assign number of industries that should be aimed for, by using the probability as a weight. */
2194 while (total_amount > 0) {
2195 uint32 r = RandomRange(total_prob);
2196 IndustryType it = 0;
2197 while (r >= this->builddata[it].probability) {
2198 r -= this->builddata[it].probability;
2199 it++;
2200 assert(it < NUM_INDUSTRYTYPES);
2202 assert(this->builddata[it].probability > 0);
2203 this->builddata[it].target_count++;
2204 total_amount--;
2209 * Try to create a random industry, during gameplay
2211 void IndustryBuildData::TryBuildNewIndustry()
2213 this->SetupTargetCount();
2215 int missing = 0; // Number of industries that need to be build.
2216 uint count = 0; // Number of industry types eligible for build.
2217 uint32 total_prob = 0; // Sum of probabilities.
2218 IndustryType forced_build = NUM_INDUSTRYTYPES; // Industry type that should be forcibly build.
2219 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2220 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
2221 missing += difference;
2222 if (this->builddata[it].wait_count > 0) continue; // This type may not be built now.
2223 if (difference > 0) {
2224 if (Industry::GetIndustryTypeCount(it) == 0 && this->builddata[it].min_number > 0) {
2225 /* An industry that should exist at least once, is not available. Force it, trying the most needed one first. */
2226 if (forced_build == NUM_INDUSTRYTYPES ||
2227 difference > this->builddata[forced_build].target_count - Industry::GetIndustryTypeCount(forced_build)) {
2228 forced_build = it;
2231 total_prob += difference;
2232 count++;
2236 if (EconomyIsInRecession() || (forced_build == NUM_INDUSTRYTYPES && (missing <= 0 || total_prob == 0))) count = 0; // Skip creation of an industry.
2238 if (count >= 1) {
2239 /* If not forced, pick a weighted random industry to build.
2240 * For the case that count == 1, there is no need to draw a random number. */
2241 IndustryType it;
2242 if (forced_build != NUM_INDUSTRYTYPES) {
2243 it = forced_build;
2244 } else {
2245 /* Non-forced, select an industry type to build (weighted random). */
2246 uint32 r = 0; // Initialized to silence the compiler.
2247 if (count > 1) r = RandomRange(total_prob);
2248 for (it = 0; it < NUM_INDUSTRYTYPES; it++) {
2249 if (this->builddata[it].wait_count > 0) continue; // Type may not be built now.
2250 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
2251 if (difference <= 0) continue; // Too many of this kind.
2252 if (count == 1) break;
2253 if (r < (uint)difference) break;
2254 r -= difference;
2256 assert(it < NUM_INDUSTRYTYPES && this->builddata[it].target_count > Industry::GetIndustryTypeCount(it));
2259 /* Try to create the industry. */
2260 const Industry *ind = PlaceIndustry(it, IACT_RANDOMCREATION, false);
2261 if (ind == NULL) {
2262 this->builddata[it].wait_count = this->builddata[it].max_wait + 1; // Compensate for decrementing below.
2263 this->builddata[it].max_wait = min(1000, this->builddata[it].max_wait + 2);
2264 } else {
2265 AdvertiseIndustryOpening(ind);
2266 this->builddata[it].max_wait = max(this->builddata[it].max_wait / 2, 1); // Reduce waiting time of the industry type.
2270 /* Decrement wait counters. */
2271 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2272 if (this->builddata[it].wait_count > 0) this->builddata[it].wait_count--;
2277 * Protects an industry from closure if the appropriate flags and conditions are met
2278 * INDUSTRYBEH_CANCLOSE_LASTINSTANCE must be set (which, by default, it is not) and the
2279 * count of industries of this type must one (or lower) in order to be protected
2280 * against closure.
2281 * @param type IndustryType been queried
2282 * @result true if protection is on, false otherwise (except for oil wells)
2284 static bool CheckIndustryCloseDownProtection(IndustryType type)
2286 const IndustrySpec *indspec = GetIndustrySpec(type);
2288 /* oil wells (or the industries with that flag set) are always allowed to closedown */
2289 if ((indspec->behaviour & INDUSTRYBEH_DONT_INCR_PROD) && _settings_game.game_creation.landscape == LT_TEMPERATE) return false;
2290 return (indspec->behaviour & INDUSTRYBEH_CANCLOSE_LASTINSTANCE) == 0 && Industry::GetIndustryTypeCount(type) <= 1;
2294 * Can given cargo type be accepted or produced by the industry?
2295 * @param cargo: Cargo type
2296 * @param ind: Industry
2297 * @param *c_accepts: Pointer to boolean for acceptance of cargo
2298 * @param *c_produces: Pointer to boolean for production of cargo
2299 * @return: \c *c_accepts is set when industry accepts the cargo type,
2300 * \c *c_produces is set when the industry produces the cargo type
2302 static void CanCargoServiceIndustry(CargoID cargo, Industry *ind, bool *c_accepts, bool *c_produces)
2304 if (cargo == CT_INVALID) return;
2306 /* Check for acceptance of cargo */
2307 for (byte j = 0; j < lengthof(ind->accepts_cargo); j++) {
2308 if (cargo == ind->accepts_cargo[j] && !IndustryTemporarilyRefusesCargo(ind, cargo)) {
2309 *c_accepts = true;
2310 break;
2314 /* Check for produced cargo */
2315 for (byte j = 0; j < lengthof(ind->produced_cargo); j++) {
2316 if (cargo == ind->produced_cargo[j]) {
2317 *c_produces = true;
2318 break;
2324 * Compute who can service the industry.
2326 * Here, 'can service' means that he/she has trains and stations close enough
2327 * to the industry with the right cargo type and the right orders (ie has the
2328 * technical means).
2330 * @param ind: Industry being investigated.
2332 * @return: 0 if nobody can service the industry, 2 if the local company can
2333 * service the industry, and 1 otherwise (only competitors can service the
2334 * industry)
2336 static int WhoCanServiceIndustry(Industry *ind)
2338 /* Find all stations within reach of the industry */
2339 StationList stations;
2340 FindStationsAroundTiles(ind->location, &stations);
2342 if (stations.Length() == 0) return 0; // No stations found at all => nobody services
2344 const Vehicle *v;
2345 int result = 0;
2346 FOR_ALL_VEHICLES(v) {
2347 /* Is it worthwhile to try this vehicle? */
2348 if (v->owner != _local_company && result != 0) continue;
2350 /* Check whether it accepts the right kind of cargo */
2351 bool c_accepts = false;
2352 bool c_produces = false;
2353 if (v->type == VEH_TRAIN && v->IsFrontEngine()) {
2354 for (const Vehicle *u = v; u != NULL; u = u->Next()) {
2355 CanCargoServiceIndustry(u->cargo_type, ind, &c_accepts, &c_produces);
2357 } else if (v->type == VEH_ROAD || v->type == VEH_SHIP || v->type == VEH_AIRCRAFT) {
2358 CanCargoServiceIndustry(v->cargo_type, ind, &c_accepts, &c_produces);
2359 } else {
2360 continue;
2362 if (!c_accepts && !c_produces) continue; // Wrong cargo
2364 /* Check orders of the vehicle.
2365 * We cannot check the first of shared orders only, since the first vehicle in such a chain
2366 * may have a different cargo type.
2368 const Order *o;
2369 FOR_VEHICLE_ORDERS(v, o) {
2370 if (o->IsType(OT_GOTO_STATION) && !(o->GetUnloadType() & OUFB_TRANSFER)) {
2371 /* Vehicle visits a station to load or unload */
2372 Station *st = Station::Get(o->GetDestination());
2373 assert(st != NULL);
2375 /* Same cargo produced by industry is dropped here => not serviced by vehicle v */
2376 if ((o->GetUnloadType() & OUFB_UNLOAD) && !c_accepts) break;
2378 if (stations.Contains(st)) {
2379 if (v->owner == _local_company) return 2; // Company services industry
2380 result = 1; // Competitor services industry
2385 return result;
2389 * Report news that industry production has changed significantly
2391 * @param ind: Industry with changed production
2392 * @param type: Cargo type that has changed
2393 * @param percent: Percentage of change (>0 means increase, <0 means decrease)
2395 static void ReportNewsProductionChangeIndustry(Industry *ind, CargoID type, int percent)
2397 NewsType nt;
2399 switch (WhoCanServiceIndustry(ind)) {
2400 case 0: nt = NT_INDUSTRY_NOBODY; break;
2401 case 1: nt = NT_INDUSTRY_OTHER; break;
2402 case 2: nt = NT_INDUSTRY_COMPANY; break;
2403 default: NOT_REACHED();
2405 SetDParam(2, abs(percent));
2406 SetDParam(0, CargoSpec::Get(type)->name);
2407 SetDParam(1, ind->index);
2408 AddIndustryNewsItem(
2409 percent >= 0 ? STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH : STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH,
2411 ind->index
2415 static const uint PERCENT_TRANSPORTED_60 = 153;
2416 static const uint PERCENT_TRANSPORTED_80 = 204;
2419 * Change industry production or do closure
2420 * @param i Industry for which changes are performed
2421 * @param monthly true if it's the monthly call, false if it's the random call
2423 static void ChangeIndustryProduction(Industry *i, bool monthly)
2425 StringID str = STR_NULL;
2426 bool closeit = false;
2427 const IndustrySpec *indspec = GetIndustrySpec(i->type);
2428 bool standard = false;
2429 bool suppress_message = false;
2430 bool recalculate_multipliers = false; ///< reinitialize production_rate to match prod_level
2431 /* don't use smooth economy for industries using production related callbacks */
2432 bool smooth_economy = indspec->UsesSmoothEconomy();
2433 byte div = 0;
2434 byte mul = 0;
2435 int8 increment = 0;
2437 bool callback_enabled = HasBit(indspec->callback_mask, monthly ? CBM_IND_MONTHLYPROD_CHANGE : CBM_IND_PRODUCTION_CHANGE);
2438 if (callback_enabled) {
2439 uint16 res = GetIndustryCallback(monthly ? CBID_INDUSTRY_MONTHLYPROD_CHANGE : CBID_INDUSTRY_PRODUCTION_CHANGE, 0, Random(), i, i->type, i->location.tile);
2440 if (res != CALLBACK_FAILED) { // failed callback means "do nothing"
2441 suppress_message = HasBit(res, 7);
2442 /* Get the custom message if any */
2443 if (HasBit(res, 8)) str = MapGRFStringID(indspec->grf_prop.grffile->grfid, GB(GetRegister(0x100), 0, 16));
2444 res = GB(res, 0, 4);
2445 switch (res) {
2446 default: NOT_REACHED();
2447 case 0x0: break; // Do nothing, but show the custom message if any
2448 case 0x1: div = 1; break; // Halve industry production. If production reaches the quarter of the default, the industry is closed instead.
2449 case 0x2: mul = 1; break; // Double industry production if it hasn't reached eight times of the original yet.
2450 case 0x3: closeit = true; break; // The industry announces imminent closure, and is physically removed from the map next month.
2451 case 0x4: standard = true; break; // Do the standard random production change as if this industry was a primary one.
2452 case 0x5: case 0x6: case 0x7: // Divide production by 4, 8, 16
2453 case 0x8: div = res - 0x3; break; // Divide production by 32
2454 case 0x9: case 0xA: case 0xB: // Multiply production by 4, 8, 16
2455 case 0xC: mul = res - 0x7; break; // Multiply production by 32
2456 case 0xD: // decrement production
2457 case 0xE: // increment production
2458 increment = res == 0x0D ? -1 : 1;
2459 break;
2460 case 0xF: // Set production to third byte of register 0x100
2461 i->prod_level = Clamp(GB(GetRegister(0x100), 16, 8), PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
2462 recalculate_multipliers = true;
2463 break;
2466 } else {
2467 if (monthly != smooth_economy) return;
2468 if (indspec->life_type == INDUSTRYLIFE_BLACK_HOLE) return;
2471 if (standard || (!callback_enabled && (indspec->life_type & (INDUSTRYLIFE_ORGANIC | INDUSTRYLIFE_EXTRACTIVE)) != 0)) {
2472 /* decrease or increase */
2473 bool only_decrease = (indspec->behaviour & INDUSTRYBEH_DONT_INCR_PROD) && _settings_game.game_creation.landscape == LT_TEMPERATE;
2475 if (smooth_economy) {
2476 closeit = true;
2477 for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
2478 if (i->produced_cargo[j] == CT_INVALID) continue;
2479 uint32 r = Random();
2480 int old_prod, new_prod, percent;
2481 /* If over 60% is transported, mult is 1, else mult is -1. */
2482 int mult = (i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_60) ? 1 : -1;
2484 new_prod = old_prod = i->production_rate[j];
2486 /* For industries with only_decrease flags (temperate terrain Oil Wells),
2487 * the multiplier will always be -1 so they will only decrease. */
2488 if (only_decrease) {
2489 mult = -1;
2490 /* For normal industries, if over 60% is transported, 33% chance for decrease.
2491 * Bonus for very high station ratings (over 80%): 16% chance for decrease. */
2492 } else if (Chance16I(1, ((i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_80) ? 6 : 3), r)) {
2493 mult *= -1;
2496 /* 4.5% chance for 3-23% (or 1 unit for very low productions) production change,
2497 * determined by mult value. If mult = 1 prod. increases, else (-1) it decreases. */
2498 if (Chance16I(1, 22, r >> 16)) {
2499 new_prod += mult * (max(((RandomRange(50) + 10) * old_prod) >> 8, 1U));
2502 /* Prevent production to overflow or Oil Rig passengers to be over-"produced" */
2503 new_prod = Clamp(new_prod, 1, 255);
2505 if (((indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0) && j == 1) {
2506 new_prod = Clamp(new_prod, 0, 16);
2509 /* Do not stop closing the industry when it has the lowest possible production rate */
2510 if (new_prod == old_prod && old_prod > 1) {
2511 closeit = false;
2512 continue;
2515 percent = (old_prod == 0) ? 100 : (new_prod * 100 / old_prod - 100);
2516 i->production_rate[j] = new_prod;
2518 /* Close the industry when it has the lowest possible production rate */
2519 if (new_prod > 1) closeit = false;
2521 if (abs(percent) >= 10) {
2522 ReportNewsProductionChangeIndustry(i, i->produced_cargo[j], percent);
2525 } else {
2526 if (only_decrease || Chance16(1, 3)) {
2527 /* If more than 60% transported, 66% chance of increase, else 33% chance of increase */
2528 if (!only_decrease && (i->last_month_pct_transported[0] > PERCENT_TRANSPORTED_60) != Chance16(1, 3)) {
2529 mul = 1; // Increase production
2530 } else {
2531 div = 1; // Decrease production
2537 if (!callback_enabled && (indspec->life_type & INDUSTRYLIFE_PROCESSING)) {
2538 if ( (byte)(_cur_year - i->last_prod_year) >= 5 && Chance16(1, smooth_economy ? 180 : 2)) {
2539 closeit = true;
2543 /* Increase if needed */
2544 while (mul-- != 0 && i->prod_level < PRODLEVEL_MAXIMUM) {
2545 i->prod_level = min(i->prod_level * 2, PRODLEVEL_MAXIMUM);
2546 recalculate_multipliers = true;
2547 if (str == STR_NULL) str = indspec->production_up_text;
2550 /* Decrease if needed */
2551 while (div-- != 0 && !closeit) {
2552 if (i->prod_level == PRODLEVEL_MINIMUM) {
2553 closeit = true;
2554 } else {
2555 i->prod_level = max(i->prod_level / 2, (int)PRODLEVEL_MINIMUM); // typecast to int required to please MSVC
2556 recalculate_multipliers = true;
2557 if (str == STR_NULL) str = indspec->production_down_text;
2561 /* Increase or Decreasing the production level if needed */
2562 if (increment != 0) {
2563 if (increment < 0 && i->prod_level == PRODLEVEL_MINIMUM) {
2564 closeit = true;
2565 } else {
2566 i->prod_level = ClampU(i->prod_level + increment, PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
2567 recalculate_multipliers = true;
2571 /* Recalculate production_rate
2572 * For non-smooth economy these should always be synchronized with prod_level */
2573 if (recalculate_multipliers) i->RecomputeProductionMultipliers();
2575 /* Close if needed and allowed */
2576 if (closeit && !CheckIndustryCloseDownProtection(i->type)) {
2577 i->prod_level = PRODLEVEL_CLOSURE;
2578 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
2579 str = indspec->closure_text;
2582 if (!suppress_message && str != STR_NULL) {
2583 NewsType nt;
2584 /* Compute news category */
2585 if (closeit) {
2586 nt = NT_INDUSTRY_CLOSE;
2587 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index));
2588 Game::NewEvent(new ScriptEventIndustryClose(i->index));
2589 } else {
2590 switch (WhoCanServiceIndustry(i)) {
2591 case 0: nt = NT_INDUSTRY_NOBODY; break;
2592 case 1: nt = NT_INDUSTRY_OTHER; break;
2593 case 2: nt = NT_INDUSTRY_COMPANY; break;
2594 default: NOT_REACHED();
2597 /* Set parameters of news string */
2598 if (str > STR_LAST_STRINGID) {
2599 SetDParam(0, STR_TOWN_NAME);
2600 SetDParam(1, i->town->index);
2601 SetDParam(2, indspec->name);
2602 } else if (closeit) {
2603 SetDParam(0, STR_FORMAT_INDUSTRY_NAME);
2604 SetDParam(1, i->town->index);
2605 SetDParam(2, indspec->name);
2606 } else {
2607 SetDParam(0, i->index);
2609 /* and report the news to the user */
2610 if (closeit) {
2611 AddTileNewsItem(str, nt, i->location.tile + TileDiffXY(1, 1));
2612 } else {
2613 AddIndustryNewsItem(str, nt, i->index);
2619 * Daily handler for the industry changes
2620 * Taking the original map size of 256*256, the number of random changes was always of just one unit.
2621 * But it cannot be the same on smaller or bigger maps. That number has to be scaled up or down.
2622 * For small maps, it implies that less than one change per month is required, while on bigger maps,
2623 * it would be way more. The daily loop handles those changes.
2625 void IndustryDailyLoop()
2627 _economy.industry_daily_change_counter += _economy.industry_daily_increment;
2629 /* Bits 16-31 of industry_construction_counter contain the number of industries to change/create today,
2630 * the lower 16 bit are a fractional part that might accumulate over several days until it
2631 * is sufficient for an industry. */
2632 uint16 change_loop = _economy.industry_daily_change_counter >> 16;
2634 /* Reset the active part of the counter, just keeping the "fractional part" */
2635 _economy.industry_daily_change_counter &= 0xFFFF;
2637 if (change_loop == 0) {
2638 return; // Nothing to do? get out
2641 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
2643 /* perform the required industry changes for the day */
2645 uint perc = 3; // Between 3% and 9% chance of creating a new industry.
2646 if ((_industry_builder.wanted_inds >> 16) > GetCurrentTotalNumberOfIndustries()) {
2647 perc = min(9u, perc + (_industry_builder.wanted_inds >> 16) - GetCurrentTotalNumberOfIndustries());
2649 for (uint16 j = 0; j < change_loop; j++) {
2650 if (Chance16(perc, 100)) {
2651 _industry_builder.TryBuildNewIndustry();
2652 } else {
2653 Industry *i = Industry::GetRandom();
2654 if (i != NULL) {
2655 ChangeIndustryProduction(i, false);
2656 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
2661 cur_company.Restore();
2663 /* production-change */
2664 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 1);
2667 void IndustryMonthlyLoop()
2669 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
2671 _industry_builder.MonthlyLoop();
2673 Industry *i;
2674 FOR_ALL_INDUSTRIES(i) {
2675 UpdateIndustryStatistics(i);
2676 if (i->prod_level == PRODLEVEL_CLOSURE) {
2677 delete i;
2678 } else {
2679 ChangeIndustryProduction(i, true);
2680 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
2684 cur_company.Restore();
2686 /* production-change */
2687 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 1);
2691 void InitializeIndustries()
2693 Industry::ResetIndustryCounts();
2694 _industry_sound_tile = 0;
2696 _industry_builder.Reset();
2700 * Is an industry with the spec a raw industry?
2701 * @return true if it should be handled as a raw industry
2703 bool IndustrySpec::IsRawIndustry() const
2705 return (this->life_type & (INDUSTRYLIFE_EXTRACTIVE | INDUSTRYLIFE_ORGANIC)) != 0;
2709 * Is an industry with the spec a processing industry?
2710 * @return true if it should be handled as a processing industry
2712 bool IndustrySpec::IsProcessingIndustry() const
2714 /* Lumber mills are neither raw nor processing */
2715 return (this->life_type & INDUSTRYLIFE_PROCESSING) != 0 &&
2716 (this->behaviour & INDUSTRYBEH_CUT_TREES) == 0;
2720 * Get the cost for constructing this industry
2721 * @return the cost (inflation corrected etc)
2723 Money IndustrySpec::GetConstructionCost() const
2725 /* Building raw industries like secondary uses different price base */
2726 return (_price[(_settings_game.construction.raw_industry_construction == 1 && this->IsRawIndustry()) ?
2727 PR_BUILD_INDUSTRY_RAW : PR_BUILD_INDUSTRY] * this->cost_multiplier) >> 8;
2731 * Get the cost for removing this industry
2732 * Take note that the cost will always be zero for non-grf industries.
2733 * Only if the grf author did specified a cost will it be applicable.
2734 * @return the cost (inflation corrected etc)
2736 Money IndustrySpec::GetRemovalCost() const
2738 return (_price[PR_CLEAR_INDUSTRY] * this->removal_cost_multiplier) >> 8;
2742 * Determines whether this industrytype uses smooth economy or whether it uses standard/newgrf production changes.
2743 * @return true if smooth economy is used.
2745 bool IndustrySpec::UsesSmoothEconomy() const
2747 return _settings_game.economy.smooth_economy &&
2748 !(HasBit(this->callback_mask, CBM_IND_PRODUCTION_256_TICKS) || HasBit(this->callback_mask, CBM_IND_PRODUCTION_CARGO_ARRIVAL)) && // production callbacks
2749 !(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
2752 static CommandCost TerraformTile_Industry(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
2754 if (AutoslopeEnabled()) {
2755 /* We imitate here TTDP's behaviour:
2756 * - Both new and old slope must not be steep.
2757 * - TileMaxZ must not be changed.
2758 * - Allow autoslope by default.
2759 * - Disallow autoslope if callback succeeds and returns non-zero.
2761 Slope tileh_old = GetTileSlope(tile);
2762 /* TileMaxZ must not be changed. Slopes must not be steep. */
2763 if (!IsSteepSlope(tileh_old) && !IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) {
2764 const IndustryGfx gfx = GetIndustryGfx(tile);
2765 const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
2767 /* Call callback 3C 'disable autosloping for industry tiles'. */
2768 if (HasBit(itspec->callback_mask, CBM_INDT_AUTOSLOPE)) {
2769 /* If the callback fails, allow autoslope. */
2770 uint16 res = GetIndustryTileCallback(CBID_INDTILE_AUTOSLOPE, 0, 0, gfx, Industry::GetByTile(tile), tile);
2771 if (res == CALLBACK_FAILED || !ConvertBooleanCallback(itspec->grf_prop.grffile, CBID_INDTILE_AUTOSLOPE, res)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
2772 } else {
2773 /* allow autoslope */
2774 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
2778 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
2781 extern const TileTypeProcs _tile_type_industry_procs = {
2782 DrawTile_Industry, // draw_tile_proc
2783 GetSlopePixelZ_Industry, // get_slope_z_proc
2784 ClearTile_Industry, // clear_tile_proc
2785 AddAcceptedCargo_Industry, // add_accepted_cargo_proc
2786 GetTileDesc_Industry, // get_tile_desc_proc
2787 NULL, // get_tile_railway_status_proc
2788 NULL, // get_tile_road_status_proc
2789 NULL, // get_tile_waterway_status_proc
2790 ClickTile_Industry, // click_tile_proc
2791 AnimateTile_Industry, // animate_tile_proc
2792 TileLoop_Industry, // tile_loop_proc
2793 ChangeTileOwner_Industry, // change_tile_owner_proc
2794 NULL, // add_produced_cargo_proc
2795 GetFoundation_Industry, // get_foundation_proc
2796 TerraformTile_Industry, // terraform_tile_proc