Keep a tileset of industries
[openttd/fttd.git] / src / industry_cmd.cpp
blob0e7b70f22d2a7346c1baa84338beff403914d534
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 template<> Industry::Pool Industry::PoolItem::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 remove_from_tileset();
144 TILE_AREA_LOOP(tile_cur, this->location) {
145 if (IsIndustryTile(tile_cur)) {
146 if (GetIndustryIndex(tile_cur) == this->index) {
147 DeleteNewGRFInspectWindow(GSF_INDUSTRYTILES, tile_cur);
149 /* MakeWaterKeepingClass() can also handle 'land' */
150 MakeWaterKeepingClass(tile_cur, OWNER_NONE);
152 } else if (IsStationTile(tile_cur) && IsOilRig(tile_cur)) {
153 DeleteOilRig(tile_cur);
157 if (GetIndustrySpec(this->type)->behaviour & INDUSTRYBEH_PLANT_FIELDS) {
158 TileArea ta(this->location.tile - TileDiffXY(min(TileX(this->location.tile), 21), min(TileY(this->location.tile), 21)), 42, 42);
159 ta.ClampToMap();
161 /* Remove the farmland and convert it to regular tiles over time. */
162 TILE_AREA_LOOP(tile_cur, ta) {
163 if (IsFieldsTile(tile_cur) &&
164 GetIndustryIndexOfField(tile_cur) == this->index) {
165 SetIndustryIndexOfField(tile_cur, INVALID_INDUSTRY);
170 /* don't let any disaster vehicle target invalid industry */
171 ReleaseDisastersTargetingIndustry(this->index);
173 /* Clear the persistent storage. */
174 delete this->psa;
176 DecIndustryTypeCount(this->type);
178 DeleteIndustryNews(this->index);
179 DeleteWindowById(WC_INDUSTRY_VIEW, this->index);
180 DeleteNewGRFInspectWindow(GSF_INDUSTRIES, this->index);
182 DeleteSubsidyWith(ST_INDUSTRY, this->index);
183 CargoPacket::InvalidateAllFrom(ST_INDUSTRY, this->index);
187 * Invalidating some stuff after removing item from the pool.
188 * @param index index of deleted item
190 void Industry::PostDestructor(size_t index)
192 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0);
193 Station::RecomputeIndustriesNearForAll();
198 * Return a random valid industry.
199 * @return random industry, NULL if there are no industries
201 /* static */ Industry *Industry::GetRandom()
203 if (Industry::GetNumItems() == 0) return NULL;
204 int num = RandomRange((uint16)Industry::GetNumItems());
205 size_t index = MAX_UVALUE(size_t);
207 while (num >= 0) {
208 num--;
209 index++;
211 /* Make sure we have a valid industry */
212 while (!Industry::IsValidID(index)) {
213 index++;
214 assert(index < Industry::GetPoolSize());
218 return Industry::Get(index);
222 static void IndustryDrawSugarMine(const TileInfo *ti)
224 if (!IsIndustryCompleted(ti->tile)) return;
226 const DrawIndustryAnimationStruct *d = &_draw_industry_spec1[GetAnimationFrame(ti->tile)];
228 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_SIEVE + d->image_1, PAL_NONE, d->x, 0);
230 if (d->image_2 != 0) {
231 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_CLOUDS + d->image_2 - 1, PAL_NONE, 8, 41);
234 if (d->image_3 != 0) {
235 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_PILE + d->image_3 - 1, PAL_NONE,
236 _drawtile_proc1[d->image_3 - 1].x, _drawtile_proc1[d->image_3 - 1].y);
240 static void IndustryDrawToffeeQuarry(const TileInfo *ti)
242 uint8 x = 0;
244 if (IsIndustryCompleted(ti->tile)) {
245 x = _industry_anim_offs_toffee[GetAnimationFrame(ti->tile)];
246 if (x == 0xFF) {
247 x = 0;
251 AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_SHOVEL, PAL_NONE, 22 - x, 24 + x);
252 AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_TOFFEE, PAL_NONE, 6, 14);
255 static void IndustryDrawBubbleGenerator( const TileInfo *ti)
257 if (IsIndustryCompleted(ti->tile)) {
258 AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_BUBBLE, PAL_NONE, 5, _industry_anim_offs_bubbles[GetAnimationFrame(ti->tile)]);
260 AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_SPRING, PAL_NONE, 3, 67);
263 static void IndustryDrawToyFactory(const TileInfo *ti)
265 const DrawIndustryAnimationStruct *d = &_industry_anim_offs_toys[GetAnimationFrame(ti->tile)];
267 if (d->image_1 != 0xFF) {
268 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_CLAY, PAL_NONE, d->x, 96 + d->image_1);
271 if (d->image_2 != 0xFF) {
272 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_ROBOT, PAL_NONE, 16 - d->image_2 * 2, 100 + d->image_2);
275 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP, PAL_NONE, 7, d->image_3);
276 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP_HOLDER, PAL_NONE, 0, 42);
279 static void IndustryDrawCoalPlantSparks(const TileInfo *ti)
281 if (IsIndustryCompleted(ti->tile)) {
282 uint8 image = GetAnimationFrame(ti->tile);
284 if (image != 0 && image < 7) {
285 AddChildSpriteScreen(image + SPR_IT_POWER_PLANT_TRANSFORMERS,
286 PAL_NONE,
287 _coal_plant_sparks[image - 1].x,
288 _coal_plant_sparks[image - 1].y
294 typedef void IndustryDrawTileProc(const TileInfo *ti);
295 static IndustryDrawTileProc * const _industry_draw_tile_procs[5] = {
296 IndustryDrawSugarMine,
297 IndustryDrawToffeeQuarry,
298 IndustryDrawBubbleGenerator,
299 IndustryDrawToyFactory,
300 IndustryDrawCoalPlantSparks,
303 static void DrawTile_Industry(TileInfo *ti)
305 IndustryGfx gfx = GetIndustryGfx(ti->tile);
306 Industry *ind = Industry::GetByTile(ti->tile);
307 const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
309 /* Retrieve pointer to the draw industry tile struct */
310 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
311 /* Draw the tile using the specialized method of newgrf industrytile.
312 * DrawNewIndustry will return false if ever the resolver could not
313 * find any sprite to display. So in this case, we will jump on the
314 * substitute gfx instead. */
315 if (indts->grf_prop.spritegroup[0] != NULL && DrawNewIndustryTile(ti, ind, gfx, indts)) {
316 return;
317 } else {
318 /* No sprite group (or no valid one) found, meaning no graphics associated.
319 * Use the substitute one instead */
320 if (indts->grf_prop.subst_id != INVALID_INDUSTRYTILE) {
321 gfx = indts->grf_prop.subst_id;
322 /* And point the industrytile spec accordingly */
323 indts = GetIndustryTileSpec(gfx);
328 const DrawBuildingsTileStruct *dits = &_industry_draw_tile_data[gfx << 2 | (indts->anim_state ?
329 GetAnimationFrame(ti->tile) & INDUSTRY_COMPLETED :
330 GetIndustryConstructionStage(ti->tile))];
332 SpriteID image = dits->ground.sprite;
334 /* DrawFoundation() modifies ti->z and ti->tileh */
335 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
337 /* If the ground sprite is the default flat water sprite, draw also canal/river borders.
338 * Do not do this if the tile's WaterClass is 'land'. */
339 if (image == SPR_FLAT_WATER_TILE && IsTileOnWater(ti->tile)) {
340 DrawWaterClassGround(ti);
341 } else {
342 DrawGroundSprite(image, GroundSpritePaletteTransform(image, dits->ground.pal, GENERAL_SPRITE_COLOUR(ind->random_colour)));
345 /* If industries are transparent and invisible, do not draw the upper part */
346 if (IsInvisibilitySet(TO_INDUSTRIES)) return;
348 /* Add industry on top of the ground? */
349 image = dits->building.sprite;
350 if (image != 0) {
351 AddSortableSpriteToDraw(image, SpriteLayoutPaletteTransform(image, dits->building.pal, GENERAL_SPRITE_COLOUR(ind->random_colour)),
352 ti->x + dits->subtile_x,
353 ti->y + dits->subtile_y,
354 dits->width,
355 dits->height,
356 dits->dz,
357 ti->z,
358 IsTransparencySet(TO_INDUSTRIES));
360 if (IsTransparencySet(TO_INDUSTRIES)) return;
364 int proc = dits->draw_proc - 1;
365 if (proc >= 0) _industry_draw_tile_procs[proc](ti);
369 static int GetSlopePixelZ_Industry(TileIndex tile, uint x, uint y)
371 return GetTileMaxPixelZ(tile);
374 static Foundation GetFoundation_Industry(TileIndex tile, Slope tileh)
376 IndustryGfx gfx = GetIndustryGfx(tile);
378 /* For NewGRF industry tiles we might not be drawing a foundation. We need to
379 * account for this, as other structures should
380 * draw the wall of the foundation in this case.
382 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
383 const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
384 if (indts->grf_prop.spritegroup[0] != NULL && HasBit(indts->callback_mask, CBM_INDT_DRAW_FOUNDATIONS)) {
385 uint32 callback_res = GetIndustryTileCallback(CBID_INDTILE_DRAW_FOUNDATIONS, 0, 0, gfx, Industry::GetByTile(tile), tile);
386 if (callback_res != CALLBACK_FAILED && !ConvertBooleanCallback(indts->grf_prop.grffile, CBID_INDTILE_DRAW_FOUNDATIONS, callback_res)) return FOUNDATION_NONE;
389 return FlatteningFoundation(tileh);
392 static void AddAcceptedCargo_Industry(TileIndex tile, CargoArray &acceptance, uint32 *always_accepted)
394 IndustryGfx gfx = GetIndustryGfx(tile);
395 const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
397 /* When we have to use a callback, we put our data in the next two variables */
398 CargoID raw_accepts_cargo[lengthof(itspec->accepts_cargo)];
399 uint8 raw_cargo_acceptance[lengthof(itspec->acceptance)];
401 /* And then these will always point to a same sized array with the required data */
402 const CargoID *accepts_cargo = itspec->accepts_cargo;
403 const uint8 *cargo_acceptance = itspec->acceptance;
405 if (HasBit(itspec->callback_mask, CBM_INDT_ACCEPT_CARGO)) {
406 uint16 res = GetIndustryTileCallback(CBID_INDTILE_ACCEPT_CARGO, 0, 0, gfx, Industry::GetByTile(tile), tile);
407 if (res != CALLBACK_FAILED) {
408 accepts_cargo = raw_accepts_cargo;
409 for (uint i = 0; i < lengthof(itspec->accepts_cargo); i++) raw_accepts_cargo[i] = GetCargoTranslation(GB(res, i * 5, 5), itspec->grf_prop.grffile);
413 if (HasBit(itspec->callback_mask, CBM_INDT_CARGO_ACCEPTANCE)) {
414 uint16 res = GetIndustryTileCallback(CBID_INDTILE_CARGO_ACCEPTANCE, 0, 0, gfx, Industry::GetByTile(tile), tile);
415 if (res != CALLBACK_FAILED) {
416 cargo_acceptance = raw_cargo_acceptance;
417 for (uint i = 0; i < lengthof(itspec->accepts_cargo); i++) raw_cargo_acceptance[i] = GB(res, i * 4, 4);
421 const Industry *ind = Industry::GetByTile(tile);
422 for (byte i = 0; i < lengthof(itspec->accepts_cargo); i++) {
423 CargoID a = accepts_cargo[i];
424 if (a == CT_INVALID || cargo_acceptance[i] == 0) continue; // work only with valid cargoes
426 /* Add accepted cargo */
427 acceptance[a] += cargo_acceptance[i];
429 /* Maybe set 'always accepted' bit (if it's not set already) */
430 if (HasBit(*always_accepted, a)) continue;
432 bool accepts = false;
433 for (uint cargo_index = 0; cargo_index < lengthof(ind->accepts_cargo); cargo_index++) {
434 /* Test whether the industry itself accepts the cargo type */
435 if (ind->accepts_cargo[cargo_index] == a) {
436 accepts = true;
437 break;
441 if (accepts) continue;
443 /* If the industry itself doesn't accept this cargo, set 'always accepted' bit */
444 SetBit(*always_accepted, a);
448 static void GetTileDesc_Industry(TileIndex tile, TileDesc *td)
450 const Industry *i = Industry::GetByTile(tile);
451 const IndustrySpec *is = GetIndustrySpec(i->type);
453 td->owner[0] = i->owner;
454 td->str = is->name;
455 if (!IsIndustryCompleted(tile)) {
456 SetDParamX(td->dparam, 0, td->str);
457 td->str = STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION;
460 if (is->grf_prop.grffile != NULL) {
461 td->grf = GetGRFConfig(is->grf_prop.grffile->grfid)->GetName();
465 static CommandCost ClearTile_Industry(TileIndex tile, DoCommandFlag flags)
467 Industry *i = Industry::GetByTile(tile);
468 const IndustrySpec *indspec = GetIndustrySpec(i->type);
470 /* water can destroy industries
471 * in editor you can bulldoze industries
472 * with magic_bulldozer cheat you can destroy industries
473 * (area around OILRIG is water, so water shouldn't flood it
475 if ((_current_company != OWNER_WATER && _game_mode != GM_EDITOR &&
476 !_cheats.magic_bulldozer.value) ||
477 ((flags & DC_AUTO) != 0) ||
478 (_current_company == OWNER_WATER &&
479 ((indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) ||
480 HasBit(GetIndustryTileSpec(GetIndustryGfx(tile))->slopes_refused, 5)))) {
481 SetDParam(1, indspec->name);
482 return_cmd_error(flags & DC_AUTO ? STR_ERROR_GENERIC_OBJECT_IN_THE_WAY : INVALID_STRING_ID);
485 if (flags & DC_EXEC) {
486 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index));
487 Game::NewEvent(new ScriptEventIndustryClose(i->index));
488 delete i;
490 return CommandCost(EXPENSES_CONSTRUCTION, indspec->GetRemovalCost());
493 static void TransportIndustryGoods(TileIndex tile)
495 Industry *i = Industry::GetByTile(tile);
496 const IndustrySpec *indspec = GetIndustrySpec(i->type);
497 bool moved_cargo = false;
499 StationFinder stations(i->location);
501 for (uint j = 0; j < lengthof(i->produced_cargo_waiting); j++) {
502 uint cw = min(i->produced_cargo_waiting[j], 255);
503 if (cw > indspec->minimal_cargo && i->produced_cargo[j] != CT_INVALID) {
504 i->produced_cargo_waiting[j] -= cw;
506 /* fluctuating economy? */
507 if (EconomyIsInRecession()) cw = (cw + 1) / 2;
509 i->this_month_production[j] += cw;
511 uint am = MoveGoodsToStation(i->produced_cargo[j], cw, ST_INDUSTRY, i->index, stations.GetStations());
512 i->this_month_transported[j] += am;
514 moved_cargo |= (am != 0);
518 if (moved_cargo && !StartStopIndustryTileAnimation(i, IAT_INDUSTRY_DISTRIBUTES_CARGO)) {
519 uint newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_production;
521 if (newgfx != INDUSTRYTILE_NOANIM) {
522 ResetIndustryConstructionStage(tile);
523 SetIndustryCompleted(tile, true);
524 SetIndustryGfx(tile, newgfx);
525 MarkTileDirtyByTile(tile);
531 static void AnimateTile_Industry(TileIndex tile)
533 IndustryGfx gfx = GetIndustryGfx(tile);
535 if (GetIndustryTileSpec(gfx)->animation.status != ANIM_STATUS_NO_ANIMATION) {
536 AnimateNewIndustryTile(tile);
537 return;
540 switch (gfx) {
541 case GFX_SUGAR_MINE_SIEVE:
542 if ((_tick_counter & 1) == 0) {
543 byte m = GetAnimationFrame(tile) + 1;
545 if (_settings_client.sound.ambient) {
546 switch (m & 7) {
547 case 2: SndPlayTileFx(SND_2D_RIP_2, tile); break;
548 case 6: SndPlayTileFx(SND_29_RIP, tile); break;
552 if (m >= 96) {
553 m = 0;
554 DeleteAnimatedTile(tile);
556 SetAnimationFrame(tile, m);
558 MarkTileDirtyByTile(tile);
560 break;
562 case GFX_TOFFEE_QUARY:
563 if ((_tick_counter & 3) == 0) {
564 byte m = GetAnimationFrame(tile);
566 if (_industry_anim_offs_toffee[m] == 0xFF && _settings_client.sound.ambient) {
567 SndPlayTileFx(SND_30_CARTOON_SOUND, tile);
570 if (++m >= 70) {
571 m = 0;
572 DeleteAnimatedTile(tile);
574 SetAnimationFrame(tile, m);
576 MarkTileDirtyByTile(tile);
578 break;
580 case GFX_BUBBLE_CATCHER:
581 if ((_tick_counter & 1) == 0) {
582 byte m = GetAnimationFrame(tile);
584 if (++m >= 40) {
585 m = 0;
586 DeleteAnimatedTile(tile);
588 SetAnimationFrame(tile, m);
590 MarkTileDirtyByTile(tile);
592 break;
594 /* Sparks on a coal plant */
595 case GFX_POWERPLANT_SPARKS:
596 if ((_tick_counter & 3) == 0) {
597 byte m = GetAnimationFrame(tile);
598 if (m == 6) {
599 SetAnimationFrame(tile, 0);
600 DeleteAnimatedTile(tile);
601 } else {
602 SetAnimationFrame(tile, m + 1);
603 MarkTileDirtyByTile(tile);
606 break;
608 case GFX_TOY_FACTORY:
609 if ((_tick_counter & 1) == 0) {
610 byte m = GetAnimationFrame(tile) + 1;
612 switch (m) {
613 case 1: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2C_MACHINERY, tile); break;
614 case 23: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2B_COMEDY_HIT, tile); break;
615 case 28: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2A_EXTRACT_AND_POP, tile); break;
616 default:
617 if (m >= 50) {
618 int n = GetIndustryAnimationLoop(tile) + 1;
619 m = 0;
620 if (n >= 8) {
621 n = 0;
622 DeleteAnimatedTile(tile);
624 SetIndustryAnimationLoop(tile, n);
628 SetAnimationFrame(tile, m);
629 MarkTileDirtyByTile(tile);
631 break;
633 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
634 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
635 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
636 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
637 if ((_tick_counter & 3) == 0) {
638 IndustryGfx gfx = GetIndustryGfx(tile);
640 gfx = (gfx < 155) ? gfx + 1 : 148;
641 SetIndustryGfx(tile, gfx);
642 MarkTileDirtyByTile(tile);
644 break;
646 case GFX_OILWELL_ANIMATED_1:
647 case GFX_OILWELL_ANIMATED_2:
648 case GFX_OILWELL_ANIMATED_3:
649 if ((_tick_counter & 7) == 0) {
650 bool b = Chance16(1, 7);
651 IndustryGfx gfx = GetIndustryGfx(tile);
653 byte m = GetAnimationFrame(tile) + 1;
654 if (m == 4 && (m = 0, ++gfx) == GFX_OILWELL_ANIMATED_3 + 1 && (gfx = GFX_OILWELL_ANIMATED_1, b)) {
655 SetIndustryGfx(tile, GFX_OILWELL_NOT_ANIMATED);
656 SetIndustryConstructionStage(tile, 3);
657 DeleteAnimatedTile(tile);
658 } else {
659 SetAnimationFrame(tile, m);
660 SetIndustryGfx(tile, gfx);
661 MarkTileDirtyByTile(tile);
664 break;
666 case GFX_COAL_MINE_TOWER_ANIMATED:
667 case GFX_COPPER_MINE_TOWER_ANIMATED:
668 case GFX_GOLD_MINE_TOWER_ANIMATED: {
669 int state = _tick_counter & 0x7FF;
671 if ((state -= 0x400) < 0) return;
673 if (state < 0x1A0) {
674 if (state < 0x20 || state >= 0x180) {
675 byte m = GetAnimationFrame(tile);
676 if (!(m & 0x40)) {
677 SetAnimationFrame(tile, m | 0x40);
678 if (_settings_client.sound.ambient) SndPlayTileFx(SND_0B_MINING_MACHINERY, tile);
680 if (state & 7) return;
681 } else {
682 if (state & 3) return;
684 byte m = (GetAnimationFrame(tile) + 1) | 0x40;
685 if (m > 0xC2) m = 0xC0;
686 SetAnimationFrame(tile, m);
687 MarkTileDirtyByTile(tile);
688 } else if (state >= 0x200 && state < 0x3A0) {
689 int i = (state < 0x220 || state >= 0x380) ? 7 : 3;
690 if (state & i) return;
692 byte m = (GetAnimationFrame(tile) & 0xBF) - 1;
693 if (m < 0x80) m = 0x82;
694 SetAnimationFrame(tile, m);
695 MarkTileDirtyByTile(tile);
697 break;
702 static void CreateChimneySmoke(TileIndex tile)
704 uint x = TileX(tile) * TILE_SIZE;
705 uint y = TileY(tile) * TILE_SIZE;
706 int z = GetTileMaxPixelZ(tile);
708 CreateEffectVehicle(x + 15, y + 14, z + 59, EV_CHIMNEY_SMOKE);
711 static void MakeIndustryTileBigger(TileIndex tile)
713 byte cnt = GetIndustryConstructionCounter(tile) + 1;
714 if (cnt != 4) {
715 SetIndustryConstructionCounter(tile, cnt);
716 return;
719 byte stage = GetIndustryConstructionStage(tile) + 1;
720 SetIndustryConstructionCounter(tile, 0);
721 SetIndustryConstructionStage(tile, stage);
722 StartStopIndustryTileAnimation(tile, IAT_CONSTRUCTION_STATE_CHANGE);
723 if (stage == INDUSTRY_COMPLETED) SetIndustryCompleted(tile, true);
725 MarkTileDirtyByTile(tile);
727 if (!IsIndustryCompleted(tile)) return;
729 IndustryGfx gfx = GetIndustryGfx(tile);
730 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
731 /* New industries are already animated on construction. */
732 return;
735 switch (gfx) {
736 case GFX_POWERPLANT_CHIMNEY:
737 CreateChimneySmoke(tile);
738 break;
740 case GFX_OILRIG_1: {
741 /* Do not require an industry tile to be after the first two GFX_OILRIG_1
742 * tiles (like the default oil rig). Do a proper check to ensure the
743 * tiles belong to the same industry and based on that build the oil rig's
744 * station. */
745 TileIndex other = tile + TileDiffXY(0, 1);
747 if (IsIndustryTile(other) &&
748 GetIndustryGfx(other) == GFX_OILRIG_1 &&
749 GetIndustryIndex(tile) == GetIndustryIndex(other)) {
750 BuildOilRig(tile);
752 break;
755 case GFX_TOY_FACTORY:
756 case GFX_BUBBLE_CATCHER:
757 case GFX_TOFFEE_QUARY:
758 SetAnimationFrame(tile, 0);
759 SetIndustryAnimationLoop(tile, 0);
760 break;
762 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
763 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
764 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
765 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
766 AddAnimatedTile(tile);
767 break;
771 static void TileLoopIndustry_BubbleGenerator(TileIndex tile)
773 static const int8 _bubble_spawn_location[3][4] = {
774 { 11, 0, -4, -14 },
775 { -4, -10, -4, 1 },
776 { 49, 59, 60, 65 },
779 if (_settings_client.sound.ambient) SndPlayTileFx(SND_2E_EXTRACT_AND_POP, tile);
781 int dir = Random() & 3;
783 EffectVehicle *v = CreateEffectVehicleAbove(
784 TileX(tile) * TILE_SIZE + _bubble_spawn_location[0][dir],
785 TileY(tile) * TILE_SIZE + _bubble_spawn_location[1][dir],
786 _bubble_spawn_location[2][dir],
787 EV_BUBBLE
790 if (v != NULL) v->animation_substate = dir;
793 static void TileLoop_Industry(TileIndex tile)
795 if (IsTileOnWater(tile)) TileLoop_Water(tile);
797 /* Normally this doesn't happen, but if an industry NewGRF is removed
798 * an industry that was previously build on water can now be flooded.
799 * If this happens the tile is no longer an industry tile after
800 * returning from TileLoop_Water. */
801 if (!IsIndustryTile(tile)) return;
803 TriggerIndustryTile(tile, INDTILE_TRIGGER_TILE_LOOP);
805 if (!IsIndustryCompleted(tile)) {
806 MakeIndustryTileBigger(tile);
807 return;
810 if (_game_mode == GM_EDITOR) return;
812 TransportIndustryGoods(tile);
814 if (StartStopIndustryTileAnimation(tile, IAT_TILELOOP)) return;
816 IndustryGfx newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_next;
817 if (newgfx != INDUSTRYTILE_NOANIM) {
818 ResetIndustryConstructionStage(tile);
819 SetIndustryGfx(tile, newgfx);
820 MarkTileDirtyByTile(tile);
821 return;
824 IndustryGfx gfx = GetIndustryGfx(tile);
825 switch (gfx) {
826 case GFX_COAL_MINE_TOWER_NOT_ANIMATED:
827 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED:
828 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED:
829 if (!(_tick_counter & 0x400) && Chance16(1, 2)) {
830 switch (gfx) {
831 case GFX_COAL_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COAL_MINE_TOWER_ANIMATED; break;
832 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_ANIMATED; break;
833 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_ANIMATED; break;
835 SetIndustryGfx(tile, gfx);
836 SetAnimationFrame(tile, 0x80);
837 AddAnimatedTile(tile);
839 break;
841 case GFX_OILWELL_NOT_ANIMATED:
842 if (Chance16(1, 6)) {
843 SetIndustryGfx(tile, GFX_OILWELL_ANIMATED_1);
844 SetAnimationFrame(tile, 0);
845 AddAnimatedTile(tile);
847 break;
849 case GFX_COAL_MINE_TOWER_ANIMATED:
850 case GFX_COPPER_MINE_TOWER_ANIMATED:
851 case GFX_GOLD_MINE_TOWER_ANIMATED:
852 if (!(_tick_counter & 0x400)) {
853 switch (gfx) {
854 case GFX_COAL_MINE_TOWER_ANIMATED: gfx = GFX_COAL_MINE_TOWER_NOT_ANIMATED; break;
855 case GFX_COPPER_MINE_TOWER_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_NOT_ANIMATED; break;
856 case GFX_GOLD_MINE_TOWER_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_NOT_ANIMATED; break;
858 SetIndustryGfx(tile, gfx);
859 SetIndustryCompleted(tile, true);
860 SetIndustryConstructionStage(tile, 3);
861 DeleteAnimatedTile(tile);
863 break;
865 case GFX_POWERPLANT_SPARKS:
866 if (Chance16(1, 3)) {
867 if (_settings_client.sound.ambient) SndPlayTileFx(SND_0C_ELECTRIC_SPARK, tile);
868 AddAnimatedTile(tile);
870 break;
872 case GFX_COPPER_MINE_CHIMNEY:
873 CreateEffectVehicleAbove(TileX(tile) * TILE_SIZE + 6, TileY(tile) * TILE_SIZE + 6, 43, EV_COPPER_MINE_SMOKE);
874 break;
877 case GFX_TOY_FACTORY: {
878 Industry *i = Industry::GetByTile(tile);
879 if (i->was_cargo_delivered) {
880 i->was_cargo_delivered = false;
881 SetIndustryAnimationLoop(tile, 0);
882 AddAnimatedTile(tile);
885 break;
887 case GFX_BUBBLE_GENERATOR:
888 TileLoopIndustry_BubbleGenerator(tile);
889 break;
891 case GFX_TOFFEE_QUARY:
892 AddAnimatedTile(tile);
893 break;
895 case GFX_SUGAR_MINE_SIEVE:
896 if (Chance16(1, 3)) AddAnimatedTile(tile);
897 break;
901 static bool ClickTile_Industry(TileIndex tile)
903 ShowIndustryViewWindow(GetIndustryIndex(tile));
904 return true;
907 static void ChangeTileOwner_Industry(TileIndex tile, Owner old_owner, Owner new_owner)
909 /* If the founder merges, the industry was created by the merged company */
910 Industry *i = Industry::GetByTile(tile);
911 if (i->founder == old_owner) i->founder = (new_owner == INVALID_OWNER) ? OWNER_NONE : new_owner;
915 * Check whether the tile is a forest.
916 * @param tile the tile to investigate.
917 * @return true if and only if the tile is a forest
919 bool IsTileForestIndustry(TileIndex tile)
921 /* Check for industry tile */
922 if (!IsIndustryTile(tile)) return false;
924 const Industry *ind = Industry::GetByTile(tile);
926 /* Check for organic industry (i.e. not processing or extractive) */
927 if ((GetIndustrySpec(ind->type)->life_type & INDUSTRYLIFE_ORGANIC) == 0) return false;
929 /* Check for wood production */
930 for (uint i = 0; i < lengthof(ind->produced_cargo); i++) {
931 /* The industry produces wood. */
932 if (ind->produced_cargo[i] != CT_INVALID && CargoSpec::Get(ind->produced_cargo[i])->label == 'WOOD') return true;
935 return false;
938 static const byte _plantfarmfield_type[] = {1, 1, 1, 1, 1, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6};
940 static bool IsValidFarmFieldTile(TileIndex tile, bool allow_fields)
942 if (!IsGroundTile(tile)) return false;
944 return IsFieldsTile(tile) ? allow_fields :
945 !IsSnowTile(tile) && !IsClearGround(tile, GROUND_DESERT) && !IsClearGround(tile, GROUND_SHORE);
948 static void SetupFarmFieldFence(TileIndex tile, int size, byte type, DiagDirection side)
950 TileIndexDiff diff = (DiagDirToAxis(side) == AXIS_Y ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
952 do {
953 tile = TILE_MASK(tile);
955 if (IsFieldsTile(tile)) {
956 byte or_ = type;
958 if (or_ == 1 && Chance16(1, 7)) or_ = 2;
960 SetFence(tile, side, or_);
963 tile += diff;
964 } while (--size);
967 static void PlantFarmField(TileIndex tile, IndustryID industry)
969 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
970 if (GetTileZ(tile) + 2 >= GetSnowLine()) return;
973 /* determine field size */
974 uint32 r = (Random() & 0x303) + 0x404;
975 if (_settings_game.game_creation.landscape == LT_ARCTIC) r += 0x404;
976 uint size_x = GB(r, 0, 8);
977 uint size_y = GB(r, 8, 8);
979 TileArea ta(tile - TileDiffXY(min(TileX(tile), size_x / 2), min(TileY(tile), size_y / 2)), size_x, size_y);
980 ta.ClampToMap();
982 if (ta.w == 0 || ta.h == 0) return;
984 /* check the amount of bad tiles */
985 int count = 0;
986 TILE_AREA_LOOP(cur_tile, ta) {
987 assert(cur_tile < MapSize());
988 count += IsValidFarmFieldTile(cur_tile, false);
990 if (count * 2 < ta.w * ta.h) return;
992 /* determine type of field */
993 r = Random();
994 uint counter = GB(r, 5, 3);
995 uint field_type = GB(r, 8, 8) * 9 >> 8;
997 /* make field */
998 TILE_AREA_LOOP(cur_tile, ta) {
999 assert(cur_tile < MapSize());
1000 if (IsValidFarmFieldTile(cur_tile, true)) {
1001 MakeField(cur_tile, field_type, industry);
1002 SetClearCounter(cur_tile, counter);
1003 MarkTileDirtyByTile(cur_tile);
1007 int type = 3;
1008 if (_settings_game.game_creation.landscape != LT_ARCTIC && _settings_game.game_creation.landscape != LT_TROPIC) {
1009 type = _plantfarmfield_type[Random() & 0xF];
1012 SetupFarmFieldFence(ta.tile, ta.h, type, DIAGDIR_NE);
1013 SetupFarmFieldFence(ta.tile, ta.w, type, DIAGDIR_NW);
1014 SetupFarmFieldFence(ta.tile + TileDiffXY(ta.w - 1, 0), ta.h, type, DIAGDIR_SW);
1015 SetupFarmFieldFence(ta.tile + TileDiffXY(0, ta.h - 1), ta.w, type, DIAGDIR_SE);
1018 void PlantRandomFarmField(const Industry *i)
1020 int x = i->location.w / 2 + Random() % 31 - 16;
1021 int y = i->location.h / 2 + Random() % 31 - 16;
1023 TileIndex tile = TileAddWrap(i->location.tile, x, y);
1025 if (tile != INVALID_TILE) PlantFarmField(tile, i->index);
1029 * Search callback function for ChopLumberMillTrees
1030 * @param tile to test
1031 * @param user_data that is passed by the caller. In this case, nothing
1032 * @return the result of the test
1034 static bool SearchLumberMillTrees(TileIndex tile, void *user_data)
1036 if (IsTreeTile(tile) && GetTreeGrowth(tile) > 2) { ///< 3 and up means all fully grown trees
1037 /* found a tree */
1039 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
1041 _industry_sound_ctr = 1;
1042 _industry_sound_tile = tile;
1043 if (_settings_client.sound.ambient) SndPlayTileFx(SND_38_CHAINSAW, tile);
1045 DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
1047 cur_company.Restore();
1048 return true;
1050 return false;
1054 * Perform a circular search around the Lumber Mill in order to find trees to cut
1055 * @param i industry
1057 static void ChopLumberMillTrees(Industry *i)
1059 /* We only want to cut trees if all tiles are completed. */
1060 TILE_AREA_LOOP(tile_cur, i->location) {
1061 if (i->TileBelongsToIndustry(tile_cur)) {
1062 if (!IsIndustryCompleted(tile_cur)) return;
1066 TileIndex tile = i->location.tile;
1067 if (CircularTileSearch(&tile, 40, SearchLumberMillTrees, NULL)) { // 40x40 tiles to search.
1068 i->produced_cargo_waiting[0] = min(0xffff, i->produced_cargo_waiting[0] + 45); // Found a tree, add according value to waiting cargo.
1072 static void ProduceIndustryGoods(Industry *i)
1074 const IndustrySpec *indsp = GetIndustrySpec(i->type);
1076 /* play a sound? */
1077 if ((i->counter & 0x3F) == 0) {
1078 uint32 r;
1079 uint num;
1080 if (Chance16R(1, 14, r) && (num = indsp->number_of_sounds) != 0 && _settings_client.sound.ambient) {
1081 SndPlayTileFx(
1082 (SoundFx)(indsp->random_sounds[((r >> 16) * num) >> 16]),
1083 i->location.tile);
1087 i->counter--;
1089 /* produce some cargo */
1090 if ((i->counter % INDUSTRY_PRODUCE_TICKS) == 0) {
1091 if (HasBit(indsp->callback_mask, CBM_IND_PRODUCTION_256_TICKS)) IndustryProductionCallback(i, 1);
1093 IndustryBehaviour indbehav = indsp->behaviour;
1094 i->produced_cargo_waiting[0] = min(0xffff, i->produced_cargo_waiting[0] + i->production_rate[0]);
1095 i->produced_cargo_waiting[1] = min(0xffff, i->produced_cargo_waiting[1] + i->production_rate[1]);
1097 if ((indbehav & INDUSTRYBEH_PLANT_FIELDS) != 0) {
1098 uint16 cb_res = CALLBACK_FAILED;
1099 if (HasBit(indsp->callback_mask, CBM_IND_SPECIAL_EFFECT)) {
1100 cb_res = GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 0, i, i->type, i->location.tile);
1103 bool plant;
1104 if (cb_res != CALLBACK_FAILED) {
1105 plant = ConvertBooleanCallback(indsp->grf_prop.grffile, CBID_INDUSTRY_SPECIAL_EFFECT, cb_res);
1106 } else {
1107 plant = Chance16(1, 8);
1110 if (plant) PlantRandomFarmField(i);
1112 if ((indbehav & INDUSTRYBEH_CUT_TREES) != 0) {
1113 uint16 cb_res = CALLBACK_FAILED;
1114 if (HasBit(indsp->callback_mask, CBM_IND_SPECIAL_EFFECT)) {
1115 cb_res = GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 1, i, i->type, i->location.tile);
1118 bool cut;
1119 if (cb_res != CALLBACK_FAILED) {
1120 cut = ConvertBooleanCallback(indsp->grf_prop.grffile, CBID_INDUSTRY_SPECIAL_EFFECT, cb_res);
1121 } else {
1122 cut = ((i->counter % INDUSTRY_CUT_TREE_TICKS) == 0);
1125 if (cut) ChopLumberMillTrees(i);
1128 TriggerIndustry(i, INDUSTRY_TRIGGER_INDUSTRY_TICK);
1129 StartStopIndustryTileAnimation(i, IAT_INDUSTRY_TICK);
1133 void OnTick_Industry()
1135 if (_industry_sound_ctr != 0) {
1136 _industry_sound_ctr++;
1138 if (_industry_sound_ctr == 75) {
1139 if (_settings_client.sound.ambient) SndPlayTileFx(SND_37_BALLOON_SQUEAK, _industry_sound_tile);
1140 } else if (_industry_sound_ctr == 160) {
1141 _industry_sound_ctr = 0;
1142 if (_settings_client.sound.ambient) SndPlayTileFx(SND_36_CARTOON_CRASH, _industry_sound_tile);
1146 if (_game_mode == GM_EDITOR) return;
1148 Industry *i;
1149 FOR_ALL_INDUSTRIES(i) {
1150 ProduceIndustryGoods(i);
1155 * Check the conditions of #CHECK_NOTHING (Always succeeds).
1156 * @param tile %Tile to perform the checking.
1157 * @return Succeeded or failed command.
1159 static CommandCost CheckNewIndustry_NULL(TileIndex tile)
1161 return CommandCost();
1165 * Check the conditions of #CHECK_FOREST (Industry should be build above snow-line in arctic climate).
1166 * @param tile %Tile to perform the checking.
1167 * @return Succeeded or failed command.
1169 static CommandCost CheckNewIndustry_Forest(TileIndex tile)
1171 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
1172 if (GetTileZ(tile) < HighestSnowLine() + 2) {
1173 return_cmd_error(STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED);
1176 return CommandCost();
1180 * Check the conditions of #CHECK_REFINERY (Industry should be positioned near edge of the map).
1181 * @param tile %Tile to perform the checking.
1182 * @return Succeeded or failed command.
1184 static CommandCost CheckNewIndustry_OilRefinery(TileIndex tile)
1186 if (_game_mode == GM_EDITOR) return CommandCost();
1187 if (DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _settings_game.game_creation.oil_refinery_limit) return CommandCost();
1189 return_cmd_error(STR_ERROR_CAN_ONLY_BE_POSITIONED);
1192 extern bool _ignore_restrictions;
1195 * Check the conditions of #CHECK_OIL_RIG (Industries at sea should be positioned near edge of the map).
1196 * @param tile %Tile to perform the checking.
1197 * @return Succeeded or failed command.
1199 static CommandCost CheckNewIndustry_OilRig(TileIndex tile)
1201 if (_game_mode == GM_EDITOR && _ignore_restrictions) return CommandCost();
1202 if (TileHeight(tile) == 0 &&
1203 DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _settings_game.game_creation.oil_refinery_limit) return CommandCost();
1205 return_cmd_error(STR_ERROR_CAN_ONLY_BE_POSITIONED);
1209 * Check the conditions of #CHECK_FARM (Industry should be below snow-line in arctic).
1210 * @param tile %Tile to perform the checking.
1211 * @return Succeeded or failed command.
1213 static CommandCost CheckNewIndustry_Farm(TileIndex tile)
1215 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
1216 if (GetTileZ(tile) + 2 >= HighestSnowLine()) {
1217 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1220 return CommandCost();
1224 * Check the conditions of #CHECK_PLANTATION (Industry should NOT be in the desert).
1225 * @param tile %Tile to perform the checking.
1226 * @return Succeeded or failed command.
1228 static CommandCost CheckNewIndustry_Plantation(TileIndex tile)
1230 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
1231 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1233 return CommandCost();
1237 * Check the conditions of #CHECK_WATER (Industry should be in the desert).
1238 * @param tile %Tile to perform the checking.
1239 * @return Succeeded or failed command.
1241 static CommandCost CheckNewIndustry_Water(TileIndex tile)
1243 if (GetTropicZone(tile) != TROPICZONE_DESERT) {
1244 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT);
1246 return CommandCost();
1250 * Check the conditions of #CHECK_LUMBERMILL (Industry should be in the rain forest).
1251 * @param tile %Tile to perform the checking.
1252 * @return Succeeded or failed command.
1254 static CommandCost CheckNewIndustry_Lumbermill(TileIndex tile)
1256 if (GetTropicZone(tile) != TROPICZONE_RAINFOREST) {
1257 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST);
1259 return CommandCost();
1263 * Check the conditions of #CHECK_BUBBLEGEN (Industry should be in low land).
1264 * @param tile %Tile to perform the checking.
1265 * @return Succeeded or failed command.
1267 static CommandCost CheckNewIndustry_BubbleGen(TileIndex tile)
1269 if (GetTileZ(tile) > 4) {
1270 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS);
1272 return CommandCost();
1276 * Industrytype check function signature.
1277 * @param tile %Tile to check.
1278 * @return Succeeded or failed command.
1280 typedef CommandCost CheckNewIndustryProc(TileIndex tile);
1282 /** Check functions for different types of industry. */
1283 static CheckNewIndustryProc * const _check_new_industry_procs[CHECK_END] = {
1284 CheckNewIndustry_NULL, ///< CHECK_NOTHING
1285 CheckNewIndustry_Forest, ///< CHECK_FOREST
1286 CheckNewIndustry_OilRefinery, ///< CHECK_REFINERY
1287 CheckNewIndustry_Farm, ///< CHECK_FARM
1288 CheckNewIndustry_Plantation, ///< CHECK_PLANTATION
1289 CheckNewIndustry_Water, ///< CHECK_WATER
1290 CheckNewIndustry_Lumbermill, ///< CHECK_LUMBERMILL
1291 CheckNewIndustry_BubbleGen, ///< CHECK_BUBBLEGEN
1292 CheckNewIndustry_OilRig, ///< CHECK_OIL_RIG
1296 * Find a town for the industry, while checking for multiple industries in the same town.
1297 * @param tile Position of the industry to build.
1298 * @param type Industry type.
1299 * @param [out] town Pointer to return town for the new industry, \c NULL is written if no good town can be found.
1300 * @return Succeeded or failed command.
1302 * @pre \c *t != NULL
1303 * @post \c *t points to a town on success, and \c NULL on failure.
1305 static CommandCost FindTownForIndustry(TileIndex tile, int type, Town **t)
1307 *t = ClosestTownFromTile(tile);
1309 if (_settings_game.economy.multiple_industry_per_town) return CommandCost();
1311 const Industry *i;
1312 FOR_ALL_INDUSTRIES(i) {
1313 if (i->type == (byte)type && i->town == *t) {
1314 *t = NULL;
1315 return_cmd_error(STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN);
1319 return CommandCost();
1322 bool IsSlopeRefused(Slope current, Slope refused)
1324 if (IsSteepSlope(current)) return true;
1325 if (current != SLOPE_FLAT) {
1326 if (IsSteepSlope(refused)) return true;
1328 Slope t = ComplementSlope(current);
1330 if ((refused & SLOPE_W) && (t & SLOPE_NW)) return true;
1331 if ((refused & SLOPE_S) && (t & SLOPE_NE)) return true;
1332 if ((refused & SLOPE_E) && (t & SLOPE_SW)) return true;
1333 if ((refused & SLOPE_N) && (t & SLOPE_SE)) return true;
1336 return false;
1340 * Are the tiles of the industry free?
1341 * @param tile Position to check.
1342 * @param it Industry tiles table.
1343 * @param itspec_index The index of the itsepc to build/fund
1344 * @param type Type of the industry.
1345 * @param initial_random_bits The random bits the industry is going to have after construction.
1346 * @param founder Industry founder
1347 * @param creation_type The circumstances the industry is created under.
1348 * @param [out] custom_shape_check Perform custom check for the site.
1349 * @return Failed or succeeded command.
1351 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)
1353 bool refused_slope = false;
1354 bool custom_shape = false;
1356 do {
1357 IndustryGfx gfx = GetTranslatedIndustryTileID(it->gfx);
1358 TileIndex cur_tile = TileAddWrap(tile, it->ti.x, it->ti.y);
1360 if (!IsValidTile(cur_tile)) {
1361 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1364 if (gfx == GFX_WATERTILE_SPECIALCHECK) {
1365 if (!IsWaterTile(cur_tile) ||
1366 !IsTileFlat(cur_tile)) {
1367 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1369 } else {
1370 CommandCost ret = EnsureNoVehicleOnGround(cur_tile);
1371 if (ret.Failed()) return ret;
1372 if (HasBridgeAbove(cur_tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1374 const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
1376 IndustryBehaviour ind_behav = GetIndustrySpec(type)->behaviour;
1378 /* Perform land/water check if not disabled */
1379 if (!HasBit(its->slopes_refused, 5) && ((HasTileWaterClass(cur_tile) && IsTileOnWater(cur_tile)) == !(ind_behav & INDUSTRYBEH_BUILT_ONWATER))) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1381 if (HasBit(its->callback_mask, CBM_INDT_SHAPE_CHECK)) {
1382 custom_shape = true;
1383 CommandCost ret = PerformIndustryTileSlopeCheck(tile, cur_tile, its, type, gfx, itspec_index, initial_random_bits, founder, creation_type);
1384 if (ret.Failed()) return ret;
1385 } else {
1386 Slope tileh = GetTileSlope(cur_tile);
1387 refused_slope |= IsSlopeRefused(tileh, its->slopes_refused);
1390 if ((ind_behav & (INDUSTRYBEH_ONLY_INTOWN | INDUSTRYBEH_TOWN1200_MORE)) || // Tile must be a house
1391 ((ind_behav & INDUSTRYBEH_ONLY_NEARTOWN) && IsHouseTile(cur_tile))) { // Tile is allowed to be a house (and it is a house)
1392 if (!IsHouseTile(cur_tile)) {
1393 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS);
1396 /* Clear the tiles as OWNER_TOWN to not affect town rating, and to not clear protected buildings */
1397 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
1398 CommandCost ret = DoCommand(cur_tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR);
1399 cur_company.Restore();
1401 if (ret.Failed()) return ret;
1402 } else {
1403 /* Clear the tiles, but do not affect town ratings */
1404 CommandCost ret = DoCommand(cur_tile, 0, 0, DC_AUTO | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR);
1406 if (ret.Failed()) return ret;
1409 } while ((++it)->ti.x != -0x80);
1411 if (custom_shape_check != NULL) *custom_shape_check = custom_shape;
1413 /* It is almost impossible to have a fully flat land in TG, so what we
1414 * do is that we check if we can make the land flat later on. See
1415 * CheckIfCanLevelIndustryPlatform(). */
1416 if (!refused_slope || (_settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world && !custom_shape && !_ignore_restrictions)) {
1417 return CommandCost();
1419 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1423 * Is the industry allowed to be built at this place for the town?
1424 * @param tile Tile to construct the industry.
1425 * @param type Type of the industry.
1426 * @param t Town authority that the industry belongs to.
1427 * @return Succeeded or failed command.
1429 static CommandCost CheckIfIndustryIsAllowed(TileIndex tile, int type, const Town *t)
1431 if ((GetIndustrySpec(type)->behaviour & INDUSTRYBEH_TOWN1200_MORE) && t->cache.population < 1200) {
1432 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200);
1435 if ((GetIndustrySpec(type)->behaviour & INDUSTRYBEH_ONLY_NEARTOWN) && DistanceMax(t->xy, tile) > 9) {
1436 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER);
1439 return CommandCost();
1442 static bool CheckCanTerraformSurroundingTiles(TileIndex tile, uint height, int internal)
1444 /* Check if we don't leave the map */
1445 if (TileX(tile) == 0 || TileY(tile) == 0 || IsVoidTile(tile)) return false;
1447 TileArea ta(tile - TileDiffXY(1, 1), 2, 2);
1448 TILE_AREA_LOOP(tile_walk, ta) {
1449 uint curh = TileHeight(tile_walk);
1450 /* Is the tile clear? */
1451 if (!IsGroundTile(tile_walk)) return false;
1453 /* Don't allow too big of a change if this is the sub-tile check */
1454 if (internal != 0 && Delta(curh, height) > 1) return false;
1456 /* Different height, so the surrounding tiles of this tile
1457 * has to be correct too (in level, or almost in level)
1458 * else you get a chain-reaction of terraforming. */
1459 if (internal == 0 && curh != height) {
1460 if (TileX(tile_walk) == 0 || TileY(tile_walk) == 0 || !CheckCanTerraformSurroundingTiles(tile_walk + TileDiffXY(-1, -1), height, internal + 1)) {
1461 return false;
1466 return true;
1470 * This function tries to flatten out the land below an industry, without
1471 * damaging the surroundings too much.
1473 static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, DoCommandFlag flags, const IndustryTileTable *it, int type)
1475 const int MKEND = -0x80; // used for last element in an IndustryTileTable (see build_industry.h)
1476 int max_x = 0;
1477 int max_y = 0;
1479 /* Finds dimensions of largest variant of this industry */
1480 do {
1481 if (it->gfx == 0xFF) continue; // FF been a marquer for a check on clear water, skip it
1482 if (it->ti.x > max_x) max_x = it->ti.x;
1483 if (it->ti.y > max_y) max_y = it->ti.y;
1484 } while ((++it)->ti.x != MKEND);
1486 /* Remember level height */
1487 uint h = TileHeight(tile);
1489 if (TileX(tile) <= _settings_game.construction.industry_platform + 1U || TileY(tile) <= _settings_game.construction.industry_platform + 1U) return false;
1490 /* Check that all tiles in area and surrounding are clear
1491 * this determines that there are no obstructing items */
1493 TileArea ta(tile + TileDiffXY(-_settings_game.construction.industry_platform, -_settings_game.construction.industry_platform),
1494 max_x + 2 + 2 * _settings_game.construction.industry_platform, max_y + 2 + 2 * _settings_game.construction.industry_platform);
1496 if (TileX(ta.tile) + ta.w >= MapMaxX() || TileY(ta.tile) + ta.h >= MapMaxY()) return false;
1498 /* _current_company is OWNER_NONE for randomly generated industries and in editor, or the company who funded or prospected the industry.
1499 * Perform terraforming as OWNER_TOWN to disable autoslope and town ratings. */
1500 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
1502 TILE_AREA_LOOP(tile_walk, ta) {
1503 uint curh = TileHeight(tile_walk);
1504 if (curh != h) {
1505 /* This tile needs terraforming. Check if we can do that without
1506 * damaging the surroundings too much. */
1507 if (!CheckCanTerraformSurroundingTiles(tile_walk, h, 0)) {
1508 cur_company.Restore();
1509 return false;
1511 /* This is not 100% correct check, but the best we can do without modifying the map.
1512 * What is missing, is if the difference in height is more than 1.. */
1513 if (DoCommand(tile_walk, SLOPE_N, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND).Failed()) {
1514 cur_company.Restore();
1515 return false;
1520 if (flags & DC_EXEC) {
1521 /* Terraform the land under the industry */
1522 TILE_AREA_LOOP(tile_walk, ta) {
1523 uint curh = TileHeight(tile_walk);
1524 while (curh != h) {
1525 /* We give the terraforming for free here, because we can't calculate
1526 * exact cost in the test-round, and as we all know, that will cause
1527 * a nice assert if they don't match ;) */
1528 DoCommand(tile_walk, SLOPE_N, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND);
1529 curh += (curh > h) ? -1 : 1;
1534 cur_company.Restore();
1535 return true;
1540 * Check that the new industry is far enough from conflicting industries.
1541 * @param tile Tile to construct the industry.
1542 * @param type Type of the new industry.
1543 * @return Succeeded or failed command.
1545 static CommandCost CheckIfFarEnoughFromConflictingIndustry(TileIndex tile, int type)
1547 const IndustrySpec *indspec = GetIndustrySpec(type);
1549 for (Industry::TileSet::Iterator iter (&Industry::set, tile, 14); iter.get_item() != NULL; iter.next()) {
1550 const Industry *i = iter.get_item();
1552 /* Within 14 tiles from another industry is considered close */
1553 if (DistanceMax(tile, i->location.tile) > 14) continue;
1555 /* check if there are any conflicting industry types around */
1556 if (i->type == indspec->conflicting[0] ||
1557 i->type == indspec->conflicting[1] ||
1558 i->type == indspec->conflicting[2]) {
1559 return_cmd_error(STR_ERROR_INDUSTRY_TOO_CLOSE);
1562 return CommandCost();
1566 * Advertise about a new industry opening.
1567 * @param ind Industry being opened.
1569 static void AdvertiseIndustryOpening(const Industry *ind)
1571 const IndustrySpec *ind_spc = GetIndustrySpec(ind->type);
1572 SetDParam(0, ind_spc->name);
1573 if (ind_spc->new_industry_text > STR_LAST_STRINGID) {
1574 SetDParam(1, STR_TOWN_NAME);
1575 SetDParam(2, ind->town->index);
1576 } else {
1577 SetDParam(1, ind->town->index);
1579 AddIndustryNewsItem(ind_spc->new_industry_text, NT_INDUSTRY_OPEN, ind->index);
1580 AI::BroadcastNewEvent(new ScriptEventIndustryOpen(ind->index));
1581 Game::NewEvent(new ScriptEventIndustryOpen(ind->index));
1585 * Put an industry on the map.
1586 * @param i Just allocated poolitem, mostly empty.
1587 * @param tile North tile of the industry.
1588 * @param type Type of the industry.
1589 * @param it Industrylayout to build.
1590 * @param layout Number of the layout.
1591 * @param t Nearest town.
1592 * @param founder Founder of the industry; OWNER_NONE in case of random construction.
1593 * @param initial_random_bits Random bits for the industry.
1595 static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, const IndustryTileTable *it, byte layout, Town *t, Owner founder, uint16 initial_random_bits)
1597 const IndustrySpec *indspec = GetIndustrySpec(type);
1599 i->location = TileArea(tile, 1, 1);
1600 i->type = type;
1601 Industry::IncIndustryTypeCount(type);
1603 i->produced_cargo[0] = indspec->produced_cargo[0];
1604 i->produced_cargo[1] = indspec->produced_cargo[1];
1605 i->accepts_cargo[0] = indspec->accepts_cargo[0];
1606 i->accepts_cargo[1] = indspec->accepts_cargo[1];
1607 i->accepts_cargo[2] = indspec->accepts_cargo[2];
1608 i->production_rate[0] = indspec->production_rate[0];
1609 i->production_rate[1] = indspec->production_rate[1];
1611 /* don't use smooth economy for industries using production related callbacks */
1612 if (indspec->UsesSmoothEconomy()) {
1613 i->production_rate[0] = min((RandomRange(256) + 128) * i->production_rate[0] >> 8, 255);
1614 i->production_rate[1] = min((RandomRange(256) + 128) * i->production_rate[1] >> 8, 255);
1617 i->town = t;
1618 i->owner = OWNER_NONE;
1620 uint16 r = Random();
1621 i->random_colour = GB(r, 0, 4);
1622 i->counter = GB(r, 4, 12);
1623 i->random = initial_random_bits;
1624 i->produced_cargo_waiting[0] = 0;
1625 i->produced_cargo_waiting[1] = 0;
1626 i->incoming_cargo_waiting[0] = 0;
1627 i->incoming_cargo_waiting[1] = 0;
1628 i->incoming_cargo_waiting[2] = 0;
1629 i->this_month_production[0] = 0;
1630 i->this_month_production[1] = 0;
1631 i->this_month_transported[0] = 0;
1632 i->this_month_transported[1] = 0;
1633 i->last_month_pct_transported[0] = 0;
1634 i->last_month_pct_transported[1] = 0;
1635 i->last_month_transported[0] = 0;
1636 i->last_month_transported[1] = 0;
1637 i->was_cargo_delivered = false;
1638 i->last_prod_year = _cur_year;
1639 i->founder = founder;
1641 i->construction_date = _date;
1642 i->construction_type = (_game_mode == GM_EDITOR) ? ICT_SCENARIO_EDITOR :
1643 (_generating_world ? ICT_MAP_GENERATION : ICT_NORMAL_GAMEPLAY);
1645 /* Adding 1 here makes it conform to specs of var44 of varaction2 for industries
1646 * 0 = created prior of newindustries
1647 * else, chosen layout + 1 */
1648 i->selected_layout = layout + 1;
1650 i->prod_level = PRODLEVEL_DEFAULT;
1652 /* Call callbacks after the regular fields got initialised. */
1654 if (HasBit(indspec->callback_mask, CBM_IND_PROD_CHANGE_BUILD)) {
1655 uint16 res = GetIndustryCallback(CBID_INDUSTRY_PROD_CHANGE_BUILD, 0, Random(), i, type, INVALID_TILE);
1656 if (res != CALLBACK_FAILED) {
1657 if (res < PRODLEVEL_MINIMUM || res > PRODLEVEL_MAXIMUM) {
1658 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_PROD_CHANGE_BUILD, res);
1659 } else {
1660 i->prod_level = res;
1661 i->RecomputeProductionMultipliers();
1666 if (_generating_world) {
1667 i->last_month_production[0] = i->production_rate[0] * 8;
1668 i->last_month_production[1] = i->production_rate[1] * 8;
1669 } else {
1670 i->last_month_production[0] = i->last_month_production[1] = 0;
1673 if (HasBit(indspec->callback_mask, CBM_IND_DECIDE_COLOUR)) {
1674 uint16 res = GetIndustryCallback(CBID_INDUSTRY_DECIDE_COLOUR, 0, 0, i, type, INVALID_TILE);
1675 if (res != CALLBACK_FAILED) {
1676 if (GB(res, 4, 11) != 0) ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_DECIDE_COLOUR, res);
1677 i->random_colour = GB(res, 0, 4);
1681 if (HasBit(indspec->callback_mask, CBM_IND_INPUT_CARGO_TYPES)) {
1682 for (uint j = 0; j < lengthof(i->accepts_cargo); j++) i->accepts_cargo[j] = CT_INVALID;
1683 for (uint j = 0; j < lengthof(i->accepts_cargo); j++) {
1684 uint16 res = GetIndustryCallback(CBID_INDUSTRY_INPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE);
1685 if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
1686 if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
1687 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_INPUT_CARGO_TYPES, res);
1688 break;
1690 i->accepts_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
1694 if (HasBit(indspec->callback_mask, CBM_IND_OUTPUT_CARGO_TYPES)) {
1695 for (uint j = 0; j < lengthof(i->produced_cargo); j++) i->produced_cargo[j] = CT_INVALID;
1696 for (uint j = 0; j < lengthof(i->produced_cargo); j++) {
1697 uint16 res = GetIndustryCallback(CBID_INDUSTRY_OUTPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE);
1698 if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
1699 if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
1700 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_OUTPUT_CARGO_TYPES, res);
1701 break;
1703 i->produced_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
1707 /* Plant the tiles */
1709 do {
1710 TileIndex cur_tile = tile + ToTileIndexDiff(it->ti);
1712 if (it->gfx != GFX_WATERTILE_SPECIALCHECK) {
1713 i->location.Add(cur_tile);
1715 WaterClass wc = (IsPlainWaterTile(cur_tile) ? GetWaterClass(cur_tile) : WATER_CLASS_INVALID);
1717 DoCommand(cur_tile, 0, 0, DC_EXEC | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR);
1719 MakeIndustry(cur_tile, i->index, it->gfx, Random(), wc);
1721 if (_generating_world) {
1722 SetIndustryConstructionCounter(cur_tile, 3);
1723 SetIndustryConstructionStage(cur_tile, 2);
1726 /* it->gfx is stored in the map. But the translated ID cur_gfx is the interesting one */
1727 IndustryGfx cur_gfx = GetTranslatedIndustryTileID(it->gfx);
1728 const IndustryTileSpec *its = GetIndustryTileSpec(cur_gfx);
1729 if (its->animation.status != ANIM_STATUS_NO_ANIMATION) AddAnimatedTile(cur_tile);
1731 } while ((++it)->ti.x != -0x80);
1733 if (GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_PLANT_ON_BUILT) {
1734 for (uint j = 0; j != 50; j++) PlantRandomFarmField(i);
1736 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0);
1738 Station::RecomputeIndustriesNearForAll();
1742 * Helper function for Build/Fund an industry
1743 * @param tile tile where industry is built
1744 * @param type of industry to build
1745 * @param flags of operations to conduct
1746 * @param indspec pointer to industry specifications
1747 * @param itspec_index the index of the itsepc to build/fund
1748 * @param seed random seed (possibly) used by industries
1749 * @param initial_random_bits The random bits the industry is going to have after construction.
1750 * @param founder Founder of the industry
1751 * @param creation_type The circumstances the industry is created under.
1752 * @param [out] ip Pointer to store newly created industry.
1753 * @return Succeeded or failed command.
1755 * @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.
1757 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)
1759 assert(itspec_index < indspec->num_table);
1760 const IndustryTileTable *it = indspec->table[itspec_index];
1761 bool custom_shape_check = false;
1763 *ip = NULL;
1765 SmallVector<ClearedObjectArea, 1> object_areas(_cleared_object_areas);
1766 CommandCost ret = CheckIfIndustryTilesAreFree(tile, it, itspec_index, type, random_initial_bits, founder, creation_type, &custom_shape_check);
1767 _cleared_object_areas = object_areas;
1768 if (ret.Failed()) return ret;
1770 if (HasBit(GetIndustrySpec(type)->callback_mask, CBM_IND_LOCATION)) {
1771 ret = CheckIfCallBackAllowsCreation(tile, type, itspec_index, random_var8f, random_initial_bits, founder, creation_type);
1772 } else {
1773 ret = _check_new_industry_procs[indspec->check_proc](tile);
1775 if (ret.Failed()) return ret;
1777 if (!custom_shape_check && _settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world &&
1778 !_ignore_restrictions && !CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER, it, type)) {
1779 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1782 ret = CheckIfFarEnoughFromConflictingIndustry(tile, type);
1783 if (ret.Failed()) return ret;
1785 Town *t = NULL;
1786 ret = FindTownForIndustry(tile, type, &t);
1787 if (ret.Failed()) return ret;
1788 assert(t != NULL);
1790 ret = CheckIfIndustryIsAllowed(tile, type, t);
1791 if (ret.Failed()) return ret;
1793 if (!Industry::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_INDUSTRIES);
1795 if (flags & DC_EXEC) {
1796 *ip = new Industry(tile);
1797 if (!custom_shape_check) CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER | DC_EXEC, it, type);
1798 DoCreateNewIndustry(*ip, tile, type, it, itspec_index, t, founder, random_initial_bits);
1801 return CommandCost();
1805 * Build/Fund an industry
1806 * @param tile tile where industry is built
1807 * @param flags of operations to conduct
1808 * @param p1 various bitstuffed elements
1809 * - p1 = (bit 0 - 7) - industry type see build_industry.h and see industry.h
1810 * - p1 = (bit 8 - 15) - first layout to try
1811 * - p1 = (bit 16 ) - 0 = prospect, 1 = fund (only valid if current company is DEITY)
1812 * @param p2 seed to use for desyncfree randomisations
1813 * @param text unused
1814 * @return the cost of this operation or an error
1816 CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1818 IndustryType it = GB(p1, 0, 8);
1819 if (it >= NUM_INDUSTRYTYPES) return CMD_ERROR;
1821 const IndustrySpec *indspec = GetIndustrySpec(it);
1823 /* Check if the to-be built/founded industry is available for this climate. */
1824 if (!indspec->enabled || indspec->num_table == 0) return CMD_ERROR;
1826 /* If the setting for raw-material industries is not on, you cannot build raw-material industries.
1827 * Raw material industries are industries that do not accept cargo (at least for now) */
1828 if (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 0 && indspec->IsRawIndustry()) {
1829 return CMD_ERROR;
1832 if (_game_mode != GM_EDITOR && GetIndustryProbabilityCallback(it, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, 1) == 0) {
1833 return CMD_ERROR;
1836 Randomizer randomizer;
1837 randomizer.SetSeed(p2);
1838 uint16 random_initial_bits = GB(p2, 0, 16);
1839 uint32 random_var8f = randomizer.Next();
1840 int num_layouts = indspec->num_table;
1841 CommandCost ret = CommandCost(STR_ERROR_SITE_UNSUITABLE);
1842 const bool deity_prospect = _current_company == OWNER_DEITY && !HasBit(p1, 16);
1844 Industry *ind = NULL;
1845 if (deity_prospect || (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 2 && indspec->IsRawIndustry())) {
1846 if (flags & DC_EXEC) {
1847 /* Prospected industries are build as OWNER_TOWN to not e.g. be build on owned land of the founder */
1848 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
1849 /* Prospecting has a chance to fail, however we cannot guarantee that something can
1850 * be built on the map, so the chance gets lower when the map is fuller, but there
1851 * is nothing we can really do about that. */
1852 if (deity_prospect || Random() <= indspec->prospecting_chance) {
1853 for (int i = 0; i < 5000; i++) {
1854 /* We should not have more than one Random() in a function call
1855 * because parameter evaluation order is not guaranteed in the c++ standard
1857 tile = RandomTile();
1858 /* Start with a random layout */
1859 int layout = RandomRange(num_layouts);
1860 /* Check now each layout, starting with the random one */
1861 for (int j = 0; j < num_layouts; j++) {
1862 layout = (layout + 1) % num_layouts;
1863 ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, cur_company.GetOriginalValue(), _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_PROSPECTCREATION, &ind);
1864 if (ret.Succeeded()) break;
1866 if (ret.Succeeded()) break;
1869 cur_company.Restore();
1871 } else {
1872 int layout = GB(p1, 8, 8);
1873 if (layout >= num_layouts) return CMD_ERROR;
1875 /* Check subsequently each layout, starting with the given layout in p1 */
1876 for (int i = 0; i < num_layouts; i++) {
1877 layout = (layout + 1) % num_layouts;
1878 ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, _current_company, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, &ind);
1879 if (ret.Succeeded()) break;
1882 /* If it still failed, there's no suitable layout to build here, return the error */
1883 if (ret.Failed()) return ret;
1886 if ((flags & DC_EXEC) && ind != NULL && _game_mode != GM_EDITOR) {
1887 AdvertiseIndustryOpening(ind);
1890 return CommandCost(EXPENSES_OTHER, indspec->GetConstructionCost());
1895 * Create a new industry of random layout.
1896 * @param tile The location to build the industry.
1897 * @param type The industry type to build.
1898 * @param creation_type The circumstances the industry is created under.
1899 * @return the created industry or NULL if it failed.
1901 static Industry *CreateNewIndustry(TileIndex tile, IndustryType type, IndustryAvailabilityCallType creation_type)
1903 const IndustrySpec *indspec = GetIndustrySpec(type);
1905 uint32 seed = Random();
1906 uint32 seed2 = Random();
1907 Industry *i = NULL;
1908 CommandCost ret = CreateNewIndustryHelper(tile, type, DC_EXEC, indspec, RandomRange(indspec->num_table), seed, GB(seed2, 0, 16), OWNER_NONE, creation_type, &i);
1909 assert(i != NULL || ret.Failed());
1910 return i;
1914 * Compute the appearance probability for an industry during map creation.
1915 * @param it Industry type to compute.
1916 * @param [out] force_at_least_one Returns whether at least one instance should be forced on map creation.
1917 * @return Relative probability for the industry to appear.
1919 static uint32 GetScaledIndustryGenerationProbability(IndustryType it, bool *force_at_least_one)
1921 const IndustrySpec *ind_spc = GetIndustrySpec(it);
1922 uint32 chance = ind_spc->appear_creation[_settings_game.game_creation.landscape] * 16; // * 16 to increase precision
1923 if (!ind_spc->enabled || ind_spc->num_table == 0 ||
1924 (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == ID_FUND_ONLY) ||
1925 (chance = GetIndustryProbabilityCallback(it, IACT_MAPGENERATION, chance)) == 0) {
1926 *force_at_least_one = false;
1927 return 0;
1928 } else {
1929 /* We want industries appearing at coast to appear less often on bigger maps, as length of coast increases slower than map area.
1930 * For simplicity we scale in both cases, though scaling the probabilities of all industries has no effect. */
1931 chance = (ind_spc->check_proc == CHECK_REFINERY || ind_spc->check_proc == CHECK_OIL_RIG) ? ScaleByMapPerimeter(chance) : ScaleByMapSize(chance);
1933 *force_at_least_one = (chance > 0) && !(ind_spc->behaviour & INDUSTRYBEH_NOBUILT_MAPCREATION) && (_game_mode != GM_EDITOR);
1934 return chance;
1939 * Compute the probability for constructing a new industry during game play.
1940 * @param it Industry type to compute.
1941 * @param [out] min_number Minimal number of industries that should exist at the map.
1942 * @return Relative probability for the industry to appear.
1944 static uint16 GetIndustryGamePlayProbability(IndustryType it, byte *min_number)
1946 if (_settings_game.difficulty.industry_density == ID_FUND_ONLY) {
1947 *min_number = 0;
1948 return 0;
1951 const IndustrySpec *ind_spc = GetIndustrySpec(it);
1952 byte chance = ind_spc->appear_ingame[_settings_game.game_creation.landscape];
1953 if (!ind_spc->enabled || ind_spc->num_table == 0 ||
1954 ((ind_spc->behaviour & INDUSTRYBEH_BEFORE_1950) && _cur_year > 1950) ||
1955 ((ind_spc->behaviour & INDUSTRYBEH_AFTER_1960) && _cur_year < 1960) ||
1956 (chance = GetIndustryProbabilityCallback(it, IACT_RANDOMCREATION, chance)) == 0) {
1957 *min_number = 0;
1958 return 0;
1960 *min_number = (ind_spc->behaviour & INDUSTRYBEH_CANCLOSE_LASTINSTANCE) ? 1 : 0;
1961 return chance;
1965 * Get wanted number of industries on the map.
1966 * @return Wanted number of industries at the map.
1968 static uint GetNumberOfIndustries()
1970 /* Number of industries on a 256x256 map. */
1971 static const uint16 numof_industry_table[] = {
1972 0, // none
1973 0, // minimal
1974 10, // very low
1975 25, // low
1976 55, // normal
1977 80, // high
1980 assert(lengthof(numof_industry_table) == ID_END);
1981 uint difficulty = (_game_mode != GM_EDITOR) ? _settings_game.difficulty.industry_density : (uint)ID_VERY_LOW;
1982 return min(Industry::Pool::MAX_SIZE, ScaleByMapSize(numof_industry_table[difficulty]));
1986 * Try to place the industry in the game.
1987 * Since there is no feedback why placement fails, there is no other option
1988 * than to try a few times before concluding it does not work.
1989 * @param type Industry type of the desired industry.
1990 * @param try_hard Try very hard to find a place. (Used to place at least one industry per type.)
1991 * @return Pointer to created industry, or \c NULL if creation failed.
1993 static Industry *PlaceIndustry(IndustryType type, IndustryAvailabilityCallType creation_type, bool try_hard)
1995 uint tries = try_hard ? 10000u : 2000u;
1996 for (; tries > 0; tries--) {
1997 Industry *ind = CreateNewIndustry(RandomTile(), type, creation_type);
1998 if (ind != NULL) return ind;
2000 return NULL;
2004 * Try to build a industry on the map.
2005 * @param type IndustryType of the desired industry
2006 * @param try_hard Try very hard to find a place. (Used to place at least one industry per type)
2008 static void PlaceInitialIndustry(IndustryType type, bool try_hard)
2010 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
2012 IncreaseGeneratingWorldProgress(GWP_INDUSTRY);
2013 PlaceIndustry(type, IACT_MAPGENERATION, try_hard);
2015 cur_company.Restore();
2019 * Get total number of industries existing in the game.
2020 * @return Number of industries currently in the game.
2022 static uint GetCurrentTotalNumberOfIndustries()
2024 int total = 0;
2025 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) total += Industry::GetIndustryTypeCount(it);
2026 return total;
2030 /** Reset the entry. */
2031 void IndustryTypeBuildData::Reset()
2033 this->probability = 0;
2034 this->min_number = 0;
2035 this->target_count = 0;
2036 this->max_wait = 1;
2037 this->wait_count = 0;
2040 /** Completely reset the industry build data. */
2041 void IndustryBuildData::Reset()
2043 this->wanted_inds = GetCurrentTotalNumberOfIndustries() << 16;
2045 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2046 this->builddata[it].Reset();
2050 /** Monthly update of industry build data. */
2051 void IndustryBuildData::MonthlyLoop()
2053 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.
2054 if (_settings_game.difficulty.industry_density == ID_FUND_ONLY) return; // 'no industries' setting.
2056 /* To prevent running out of unused industries for the player to connect,
2057 * add a fraction of new industries each month, but only if the manager can keep up. */
2058 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).
2059 if (GetCurrentTotalNumberOfIndustries() + max_behind >= (this->wanted_inds >> 16)) {
2060 this->wanted_inds += ScaleByMapSize(NEWINDS_PER_MONTH);
2065 * This function will create random industries during game creation.
2066 * It will scale the amount of industries by mapsize and difficulty level.
2068 void GenerateIndustries()
2070 if (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == ID_FUND_ONLY) return; // No industries in the game.
2072 uint32 industry_probs[NUM_INDUSTRYTYPES];
2073 bool force_at_least_one[NUM_INDUSTRYTYPES];
2074 uint32 total_prob = 0;
2075 uint num_forced = 0;
2077 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2078 industry_probs[it] = GetScaledIndustryGenerationProbability(it, force_at_least_one + it);
2079 total_prob += industry_probs[it];
2080 if (force_at_least_one[it]) num_forced++;
2083 uint total_amount = GetNumberOfIndustries();
2084 if (total_prob == 0 || total_amount < num_forced) {
2085 /* Only place the forced ones */
2086 total_amount = num_forced;
2089 SetGeneratingWorldProgress(GWP_INDUSTRY, total_amount);
2091 /* Try to build one industry per type independent of any probabilities */
2092 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2093 if (force_at_least_one[it]) {
2094 assert(total_amount > 0);
2095 total_amount--;
2096 PlaceInitialIndustry(it, true);
2100 /* Add the remaining industries according to their probabilities */
2101 for (uint i = 0; i < total_amount; i++) {
2102 uint32 r = RandomRange(total_prob);
2103 IndustryType it = 0;
2104 while (r >= industry_probs[it]) {
2105 r -= industry_probs[it];
2106 it++;
2107 assert(it < NUM_INDUSTRYTYPES);
2109 assert(industry_probs[it] > 0);
2110 PlaceInitialIndustry(it, false);
2112 _industry_builder.Reset();
2116 * Monthly update of industry statistics.
2117 * @param i Industry to update.
2119 static void UpdateIndustryStatistics(Industry *i)
2121 for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
2122 if (i->produced_cargo[j] != CT_INVALID) {
2123 byte pct = 0;
2124 if (i->this_month_production[j] != 0) {
2125 i->last_prod_year = _cur_year;
2126 pct = min(i->this_month_transported[j] * 256 / i->this_month_production[j], 255);
2128 i->last_month_pct_transported[j] = pct;
2130 i->last_month_production[j] = i->this_month_production[j];
2131 i->this_month_production[j] = 0;
2133 i->last_month_transported[j] = i->this_month_transported[j];
2134 i->this_month_transported[j] = 0;
2140 * Recompute #production_rate for current #prod_level.
2141 * This function is only valid when not using smooth economy.
2143 void Industry::RecomputeProductionMultipliers()
2145 const IndustrySpec *indspec = GetIndustrySpec(this->type);
2146 assert(!indspec->UsesSmoothEconomy());
2148 /* Rates are rounded up, so e.g. oilrig always produces some passengers */
2149 this->production_rate[0] = min(CeilDiv(indspec->production_rate[0] * this->prod_level, PRODLEVEL_DEFAULT), 0xFF);
2150 this->production_rate[1] = min(CeilDiv(indspec->production_rate[1] * this->prod_level, PRODLEVEL_DEFAULT), 0xFF);
2155 * Set the #probability and #min_number fields for the industry type \a it for a running game.
2156 * @param it Industry type.
2157 * @return At least one of the fields has changed value.
2159 bool IndustryTypeBuildData::GetIndustryTypeData(IndustryType it)
2161 byte min_number;
2162 uint32 probability = GetIndustryGamePlayProbability(it, &min_number);
2163 bool changed = min_number != this->min_number || probability != this->probability;
2164 this->min_number = min_number;
2165 this->probability = probability;
2166 return changed;
2169 /** Decide how many industries of each type are needed. */
2170 void IndustryBuildData::SetupTargetCount()
2172 bool changed = false;
2173 uint num_planned = 0; // Number of industries planned in the industry build data.
2174 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2175 changed |= this->builddata[it].GetIndustryTypeData(it);
2176 num_planned += this->builddata[it].target_count;
2178 uint total_amount = this->wanted_inds >> 16; // Desired total number of industries.
2179 changed |= num_planned != total_amount;
2180 if (!changed) return; // All industries are still the same, no need to re-randomize.
2182 /* Initialize the target counts. */
2183 uint force_build = 0; // Number of industries that should always be available.
2184 uint32 total_prob = 0; // Sum of probabilities.
2185 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2186 IndustryTypeBuildData *ibd = this->builddata + it;
2187 force_build += ibd->min_number;
2188 ibd->target_count = ibd->min_number;
2189 total_prob += ibd->probability;
2192 if (total_prob == 0) return; // No buildable industries.
2194 /* Subtract forced industries from the number of industries available for construction. */
2195 total_amount = (total_amount <= force_build) ? 0 : total_amount - force_build;
2197 /* Assign number of industries that should be aimed for, by using the probability as a weight. */
2198 while (total_amount > 0) {
2199 uint32 r = RandomRange(total_prob);
2200 IndustryType it = 0;
2201 while (r >= this->builddata[it].probability) {
2202 r -= this->builddata[it].probability;
2203 it++;
2204 assert(it < NUM_INDUSTRYTYPES);
2206 assert(this->builddata[it].probability > 0);
2207 this->builddata[it].target_count++;
2208 total_amount--;
2213 * Try to create a random industry, during gameplay
2215 void IndustryBuildData::TryBuildNewIndustry()
2217 this->SetupTargetCount();
2219 int missing = 0; // Number of industries that need to be build.
2220 uint count = 0; // Number of industry types eligible for build.
2221 uint32 total_prob = 0; // Sum of probabilities.
2222 IndustryType forced_build = NUM_INDUSTRYTYPES; // Industry type that should be forcibly build.
2223 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2224 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
2225 missing += difference;
2226 if (this->builddata[it].wait_count > 0) continue; // This type may not be built now.
2227 if (difference > 0) {
2228 if (Industry::GetIndustryTypeCount(it) == 0 && this->builddata[it].min_number > 0) {
2229 /* An industry that should exist at least once, is not available. Force it, trying the most needed one first. */
2230 if (forced_build == NUM_INDUSTRYTYPES ||
2231 difference > this->builddata[forced_build].target_count - Industry::GetIndustryTypeCount(forced_build)) {
2232 forced_build = it;
2235 total_prob += difference;
2236 count++;
2240 if (EconomyIsInRecession() || (forced_build == NUM_INDUSTRYTYPES && (missing <= 0 || total_prob == 0))) count = 0; // Skip creation of an industry.
2242 if (count >= 1) {
2243 /* If not forced, pick a weighted random industry to build.
2244 * For the case that count == 1, there is no need to draw a random number. */
2245 IndustryType it;
2246 if (forced_build != NUM_INDUSTRYTYPES) {
2247 it = forced_build;
2248 } else {
2249 /* Non-forced, select an industry type to build (weighted random). */
2250 uint32 r = 0; // Initialized to silence the compiler.
2251 if (count > 1) r = RandomRange(total_prob);
2252 for (it = 0; it < NUM_INDUSTRYTYPES; it++) {
2253 if (this->builddata[it].wait_count > 0) continue; // Type may not be built now.
2254 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
2255 if (difference <= 0) continue; // Too many of this kind.
2256 if (count == 1) break;
2257 if (r < (uint)difference) break;
2258 r -= difference;
2260 assert(it < NUM_INDUSTRYTYPES && this->builddata[it].target_count > Industry::GetIndustryTypeCount(it));
2263 /* Try to create the industry. */
2264 const Industry *ind = PlaceIndustry(it, IACT_RANDOMCREATION, false);
2265 if (ind == NULL) {
2266 this->builddata[it].wait_count = this->builddata[it].max_wait + 1; // Compensate for decrementing below.
2267 this->builddata[it].max_wait = min(1000, this->builddata[it].max_wait + 2);
2268 } else {
2269 AdvertiseIndustryOpening(ind);
2270 this->builddata[it].max_wait = max(this->builddata[it].max_wait / 2, 1); // Reduce waiting time of the industry type.
2274 /* Decrement wait counters. */
2275 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2276 if (this->builddata[it].wait_count > 0) this->builddata[it].wait_count--;
2281 * Protects an industry from closure if the appropriate flags and conditions are met
2282 * INDUSTRYBEH_CANCLOSE_LASTINSTANCE must be set (which, by default, it is not) and the
2283 * count of industries of this type must one (or lower) in order to be protected
2284 * against closure.
2285 * @param type IndustryType been queried
2286 * @result true if protection is on, false otherwise (except for oil wells)
2288 static bool CheckIndustryCloseDownProtection(IndustryType type)
2290 const IndustrySpec *indspec = GetIndustrySpec(type);
2292 /* oil wells (or the industries with that flag set) are always allowed to closedown */
2293 if ((indspec->behaviour & INDUSTRYBEH_DONT_INCR_PROD) && _settings_game.game_creation.landscape == LT_TEMPERATE) return false;
2294 return (indspec->behaviour & INDUSTRYBEH_CANCLOSE_LASTINSTANCE) == 0 && Industry::GetIndustryTypeCount(type) <= 1;
2298 * Can given cargo type be accepted or produced by the industry?
2299 * @param cargo: Cargo type
2300 * @param ind: Industry
2301 * @param *c_accepts: Pointer to boolean for acceptance of cargo
2302 * @param *c_produces: Pointer to boolean for production of cargo
2303 * @return: \c *c_accepts is set when industry accepts the cargo type,
2304 * \c *c_produces is set when the industry produces the cargo type
2306 static void CanCargoServiceIndustry(CargoID cargo, Industry *ind, bool *c_accepts, bool *c_produces)
2308 if (cargo == CT_INVALID) return;
2310 /* Check for acceptance of cargo */
2311 for (byte j = 0; j < lengthof(ind->accepts_cargo); j++) {
2312 if (cargo == ind->accepts_cargo[j] && !IndustryTemporarilyRefusesCargo(ind, cargo)) {
2313 *c_accepts = true;
2314 break;
2318 /* Check for produced cargo */
2319 for (byte j = 0; j < lengthof(ind->produced_cargo); j++) {
2320 if (cargo == ind->produced_cargo[j]) {
2321 *c_produces = true;
2322 break;
2328 * Compute who can service the industry.
2330 * Here, 'can service' means that he/she has trains and stations close enough
2331 * to the industry with the right cargo type and the right orders (ie has the
2332 * technical means).
2334 * @param ind: Industry being investigated.
2336 * @return: 0 if nobody can service the industry, 2 if the local company can
2337 * service the industry, and 1 otherwise (only competitors can service the
2338 * industry)
2340 static int WhoCanServiceIndustry(Industry *ind)
2342 /* Find all stations within reach of the industry */
2343 StationList stations;
2344 FindStationsAroundTiles(ind->location, &stations);
2346 if (stations.Length() == 0) return 0; // No stations found at all => nobody services
2348 const Vehicle *v;
2349 int result = 0;
2350 FOR_ALL_VEHICLES(v) {
2351 /* Is it worthwhile to try this vehicle? */
2352 if (v->owner != _local_company && result != 0) continue;
2354 /* Check whether it accepts the right kind of cargo */
2355 bool c_accepts = false;
2356 bool c_produces = false;
2357 if (v->type == VEH_TRAIN && v->IsFrontEngine()) {
2358 for (const Vehicle *u = v; u != NULL; u = u->Next()) {
2359 CanCargoServiceIndustry(u->cargo_type, ind, &c_accepts, &c_produces);
2361 } else if (v->type == VEH_ROAD || v->type == VEH_SHIP || v->type == VEH_AIRCRAFT) {
2362 CanCargoServiceIndustry(v->cargo_type, ind, &c_accepts, &c_produces);
2363 } else {
2364 continue;
2366 if (!c_accepts && !c_produces) continue; // Wrong cargo
2368 /* Check orders of the vehicle.
2369 * We cannot check the first of shared orders only, since the first vehicle in such a chain
2370 * may have a different cargo type.
2372 const Order *o;
2373 FOR_VEHICLE_ORDERS(v, o) {
2374 if (o->IsType(OT_GOTO_STATION) && !(o->GetUnloadType() & OUFB_TRANSFER)) {
2375 /* Vehicle visits a station to load or unload */
2376 Station *st = Station::Get(o->GetDestination());
2377 assert(st != NULL);
2379 /* Same cargo produced by industry is dropped here => not serviced by vehicle v */
2380 if ((o->GetUnloadType() & OUFB_UNLOAD) && !c_accepts) break;
2382 if (stations.Contains(st)) {
2383 if (v->owner == _local_company) return 2; // Company services industry
2384 result = 1; // Competitor services industry
2389 return result;
2393 * Report news that industry production has changed significantly
2395 * @param ind: Industry with changed production
2396 * @param type: Cargo type that has changed
2397 * @param percent: Percentage of change (>0 means increase, <0 means decrease)
2399 static void ReportNewsProductionChangeIndustry(Industry *ind, CargoID type, int percent)
2401 NewsType nt;
2403 switch (WhoCanServiceIndustry(ind)) {
2404 case 0: nt = NT_INDUSTRY_NOBODY; break;
2405 case 1: nt = NT_INDUSTRY_OTHER; break;
2406 case 2: nt = NT_INDUSTRY_COMPANY; break;
2407 default: NOT_REACHED();
2409 SetDParam(2, abs(percent));
2410 SetDParam(0, CargoSpec::Get(type)->name);
2411 SetDParam(1, ind->index);
2412 AddIndustryNewsItem(
2413 percent >= 0 ? STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH : STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH,
2415 ind->index
2419 static const uint PERCENT_TRANSPORTED_60 = 153;
2420 static const uint PERCENT_TRANSPORTED_80 = 204;
2423 * Change industry production or do closure
2424 * @param i Industry for which changes are performed
2425 * @param monthly true if it's the monthly call, false if it's the random call
2427 static void ChangeIndustryProduction(Industry *i, bool monthly)
2429 StringID str = STR_NULL;
2430 bool closeit = false;
2431 const IndustrySpec *indspec = GetIndustrySpec(i->type);
2432 bool standard = false;
2433 bool suppress_message = false;
2434 bool recalculate_multipliers = false; ///< reinitialize production_rate to match prod_level
2435 /* don't use smooth economy for industries using production related callbacks */
2436 bool smooth_economy = indspec->UsesSmoothEconomy();
2437 byte div = 0;
2438 byte mul = 0;
2439 int8 increment = 0;
2441 bool callback_enabled = HasBit(indspec->callback_mask, monthly ? CBM_IND_MONTHLYPROD_CHANGE : CBM_IND_PRODUCTION_CHANGE);
2442 if (callback_enabled) {
2443 uint16 res = GetIndustryCallback(monthly ? CBID_INDUSTRY_MONTHLYPROD_CHANGE : CBID_INDUSTRY_PRODUCTION_CHANGE, 0, Random(), i, i->type, i->location.tile);
2444 if (res != CALLBACK_FAILED) { // failed callback means "do nothing"
2445 suppress_message = HasBit(res, 7);
2446 /* Get the custom message if any */
2447 if (HasBit(res, 8)) str = MapGRFStringID(indspec->grf_prop.grffile->grfid, GB(GetRegister(0x100), 0, 16));
2448 res = GB(res, 0, 4);
2449 switch (res) {
2450 default: NOT_REACHED();
2451 case 0x0: break; // Do nothing, but show the custom message if any
2452 case 0x1: div = 1; break; // Halve industry production. If production reaches the quarter of the default, the industry is closed instead.
2453 case 0x2: mul = 1; break; // Double industry production if it hasn't reached eight times of the original yet.
2454 case 0x3: closeit = true; break; // The industry announces imminent closure, and is physically removed from the map next month.
2455 case 0x4: standard = true; break; // Do the standard random production change as if this industry was a primary one.
2456 case 0x5: case 0x6: case 0x7: // Divide production by 4, 8, 16
2457 case 0x8: div = res - 0x3; break; // Divide production by 32
2458 case 0x9: case 0xA: case 0xB: // Multiply production by 4, 8, 16
2459 case 0xC: mul = res - 0x7; break; // Multiply production by 32
2460 case 0xD: // decrement production
2461 case 0xE: // increment production
2462 increment = res == 0x0D ? -1 : 1;
2463 break;
2464 case 0xF: // Set production to third byte of register 0x100
2465 i->prod_level = Clamp(GB(GetRegister(0x100), 16, 8), PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
2466 recalculate_multipliers = true;
2467 break;
2470 } else {
2471 if (monthly != smooth_economy) return;
2472 if (indspec->life_type == INDUSTRYLIFE_BLACK_HOLE) return;
2475 if (standard || (!callback_enabled && (indspec->life_type & (INDUSTRYLIFE_ORGANIC | INDUSTRYLIFE_EXTRACTIVE)) != 0)) {
2476 /* decrease or increase */
2477 bool only_decrease = (indspec->behaviour & INDUSTRYBEH_DONT_INCR_PROD) && _settings_game.game_creation.landscape == LT_TEMPERATE;
2479 if (smooth_economy) {
2480 closeit = true;
2481 for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
2482 if (i->produced_cargo[j] == CT_INVALID) continue;
2483 uint32 r = Random();
2484 int old_prod, new_prod, percent;
2485 /* If over 60% is transported, mult is 1, else mult is -1. */
2486 int mult = (i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_60) ? 1 : -1;
2488 new_prod = old_prod = i->production_rate[j];
2490 /* For industries with only_decrease flags (temperate terrain Oil Wells),
2491 * the multiplier will always be -1 so they will only decrease. */
2492 if (only_decrease) {
2493 mult = -1;
2494 /* For normal industries, if over 60% is transported, 33% chance for decrease.
2495 * Bonus for very high station ratings (over 80%): 16% chance for decrease. */
2496 } else if (Chance16I(1, ((i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_80) ? 6 : 3), r)) {
2497 mult *= -1;
2500 /* 4.5% chance for 3-23% (or 1 unit for very low productions) production change,
2501 * determined by mult value. If mult = 1 prod. increases, else (-1) it decreases. */
2502 if (Chance16I(1, 22, r >> 16)) {
2503 new_prod += mult * (max(((RandomRange(50) + 10) * old_prod) >> 8, 1U));
2506 /* Prevent production to overflow or Oil Rig passengers to be over-"produced" */
2507 new_prod = Clamp(new_prod, 1, 255);
2509 if (((indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0) && j == 1) {
2510 new_prod = Clamp(new_prod, 0, 16);
2513 /* Do not stop closing the industry when it has the lowest possible production rate */
2514 if (new_prod == old_prod && old_prod > 1) {
2515 closeit = false;
2516 continue;
2519 percent = (old_prod == 0) ? 100 : (new_prod * 100 / old_prod - 100);
2520 i->production_rate[j] = new_prod;
2522 /* Close the industry when it has the lowest possible production rate */
2523 if (new_prod > 1) closeit = false;
2525 if (abs(percent) >= 10) {
2526 ReportNewsProductionChangeIndustry(i, i->produced_cargo[j], percent);
2529 } else {
2530 if (only_decrease || Chance16(1, 3)) {
2531 /* If more than 60% transported, 66% chance of increase, else 33% chance of increase */
2532 if (!only_decrease && (i->last_month_pct_transported[0] > PERCENT_TRANSPORTED_60) != Chance16(1, 3)) {
2533 mul = 1; // Increase production
2534 } else {
2535 div = 1; // Decrease production
2541 if (!callback_enabled && (indspec->life_type & INDUSTRYLIFE_PROCESSING)) {
2542 if ( (byte)(_cur_year - i->last_prod_year) >= 5 && Chance16(1, smooth_economy ? 180 : 2)) {
2543 closeit = true;
2547 /* Increase if needed */
2548 while (mul-- != 0 && i->prod_level < PRODLEVEL_MAXIMUM) {
2549 i->prod_level = min(i->prod_level * 2, PRODLEVEL_MAXIMUM);
2550 recalculate_multipliers = true;
2551 if (str == STR_NULL) str = indspec->production_up_text;
2554 /* Decrease if needed */
2555 while (div-- != 0 && !closeit) {
2556 if (i->prod_level == PRODLEVEL_MINIMUM) {
2557 closeit = true;
2558 } else {
2559 i->prod_level = max(i->prod_level / 2, (int)PRODLEVEL_MINIMUM); // typecast to int required to please MSVC
2560 recalculate_multipliers = true;
2561 if (str == STR_NULL) str = indspec->production_down_text;
2565 /* Increase or Decreasing the production level if needed */
2566 if (increment != 0) {
2567 if (increment < 0 && i->prod_level == PRODLEVEL_MINIMUM) {
2568 closeit = true;
2569 } else {
2570 i->prod_level = ClampU(i->prod_level + increment, PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
2571 recalculate_multipliers = true;
2575 /* Recalculate production_rate
2576 * For non-smooth economy these should always be synchronized with prod_level */
2577 if (recalculate_multipliers) i->RecomputeProductionMultipliers();
2579 /* Close if needed and allowed */
2580 if (closeit && !CheckIndustryCloseDownProtection(i->type)) {
2581 i->prod_level = PRODLEVEL_CLOSURE;
2582 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
2583 str = indspec->closure_text;
2586 if (!suppress_message && str != STR_NULL) {
2587 NewsType nt;
2588 /* Compute news category */
2589 if (closeit) {
2590 nt = NT_INDUSTRY_CLOSE;
2591 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index));
2592 Game::NewEvent(new ScriptEventIndustryClose(i->index));
2593 } else {
2594 switch (WhoCanServiceIndustry(i)) {
2595 case 0: nt = NT_INDUSTRY_NOBODY; break;
2596 case 1: nt = NT_INDUSTRY_OTHER; break;
2597 case 2: nt = NT_INDUSTRY_COMPANY; break;
2598 default: NOT_REACHED();
2601 /* Set parameters of news string */
2602 if (str > STR_LAST_STRINGID) {
2603 SetDParam(0, STR_TOWN_NAME);
2604 SetDParam(1, i->town->index);
2605 SetDParam(2, indspec->name);
2606 } else if (closeit) {
2607 SetDParam(0, STR_FORMAT_INDUSTRY_NAME);
2608 SetDParam(1, i->town->index);
2609 SetDParam(2, indspec->name);
2610 } else {
2611 SetDParam(0, i->index);
2613 /* and report the news to the user */
2614 if (closeit) {
2615 AddTileNewsItem(str, nt, i->location.tile + TileDiffXY(1, 1));
2616 } else {
2617 AddIndustryNewsItem(str, nt, i->index);
2623 * Daily handler for the industry changes
2624 * Taking the original map size of 256*256, the number of random changes was always of just one unit.
2625 * But it cannot be the same on smaller or bigger maps. That number has to be scaled up or down.
2626 * For small maps, it implies that less than one change per month is required, while on bigger maps,
2627 * it would be way more. The daily loop handles those changes.
2629 void IndustryDailyLoop()
2631 _economy.industry_daily_change_counter += _economy.industry_daily_increment;
2633 /* Bits 16-31 of industry_construction_counter contain the number of industries to change/create today,
2634 * the lower 16 bit are a fractional part that might accumulate over several days until it
2635 * is sufficient for an industry. */
2636 uint16 change_loop = _economy.industry_daily_change_counter >> 16;
2638 /* Reset the active part of the counter, just keeping the "fractional part" */
2639 _economy.industry_daily_change_counter &= 0xFFFF;
2641 if (change_loop == 0) {
2642 return; // Nothing to do? get out
2645 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
2647 /* perform the required industry changes for the day */
2649 uint perc = 3; // Between 3% and 9% chance of creating a new industry.
2650 if ((_industry_builder.wanted_inds >> 16) > GetCurrentTotalNumberOfIndustries()) {
2651 perc = min(9u, perc + (_industry_builder.wanted_inds >> 16) - GetCurrentTotalNumberOfIndustries());
2653 for (uint16 j = 0; j < change_loop; j++) {
2654 if (Chance16(perc, 100)) {
2655 _industry_builder.TryBuildNewIndustry();
2656 } else {
2657 Industry *i = Industry::GetRandom();
2658 if (i != NULL) {
2659 ChangeIndustryProduction(i, false);
2660 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
2665 cur_company.Restore();
2667 /* production-change */
2668 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 1);
2671 void IndustryMonthlyLoop()
2673 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
2675 _industry_builder.MonthlyLoop();
2677 Industry *i;
2678 FOR_ALL_INDUSTRIES(i) {
2679 UpdateIndustryStatistics(i);
2680 if (i->prod_level == PRODLEVEL_CLOSURE) {
2681 delete i;
2682 } else {
2683 ChangeIndustryProduction(i, true);
2684 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
2688 cur_company.Restore();
2690 /* production-change */
2691 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 1);
2695 void InitializeIndustries()
2697 Industry::ResetIndustryCounts();
2698 _industry_sound_tile = 0;
2700 _industry_builder.Reset();
2704 * Is an industry with the spec a raw industry?
2705 * @return true if it should be handled as a raw industry
2707 bool IndustrySpec::IsRawIndustry() const
2709 return (this->life_type & (INDUSTRYLIFE_EXTRACTIVE | INDUSTRYLIFE_ORGANIC)) != 0;
2713 * Is an industry with the spec a processing industry?
2714 * @return true if it should be handled as a processing industry
2716 bool IndustrySpec::IsProcessingIndustry() const
2718 /* Lumber mills are neither raw nor processing */
2719 return (this->life_type & INDUSTRYLIFE_PROCESSING) != 0 &&
2720 (this->behaviour & INDUSTRYBEH_CUT_TREES) == 0;
2724 * Get the cost for constructing this industry
2725 * @return the cost (inflation corrected etc)
2727 Money IndustrySpec::GetConstructionCost() const
2729 /* Building raw industries like secondary uses different price base */
2730 return (_price[(_settings_game.construction.raw_industry_construction == 1 && this->IsRawIndustry()) ?
2731 PR_BUILD_INDUSTRY_RAW : PR_BUILD_INDUSTRY] * this->cost_multiplier) >> 8;
2735 * Get the cost for removing this industry
2736 * Take note that the cost will always be zero for non-grf industries.
2737 * Only if the grf author did specified a cost will it be applicable.
2738 * @return the cost (inflation corrected etc)
2740 Money IndustrySpec::GetRemovalCost() const
2742 return (_price[PR_CLEAR_INDUSTRY] * this->removal_cost_multiplier) >> 8;
2746 * Determines whether this industrytype uses smooth economy or whether it uses standard/newgrf production changes.
2747 * @return true if smooth economy is used.
2749 bool IndustrySpec::UsesSmoothEconomy() const
2751 return _settings_game.economy.smooth_economy &&
2752 !(HasBit(this->callback_mask, CBM_IND_PRODUCTION_256_TICKS) || HasBit(this->callback_mask, CBM_IND_PRODUCTION_CARGO_ARRIVAL)) && // production callbacks
2753 !(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
2756 static CommandCost TerraformTile_Industry(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
2758 if (AutoslopeEnabled()) {
2759 /* We imitate here TTDP's behaviour:
2760 * - Both new and old slope must not be steep.
2761 * - TileMaxZ must not be changed.
2762 * - Allow autoslope by default.
2763 * - Disallow autoslope if callback succeeds and returns non-zero.
2765 Slope tileh_old = GetTileSlope(tile);
2766 /* TileMaxZ must not be changed. Slopes must not be steep. */
2767 if (!IsSteepSlope(tileh_old) && !IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) {
2768 const IndustryGfx gfx = GetIndustryGfx(tile);
2769 const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
2771 /* Call callback 3C 'disable autosloping for industry tiles'. */
2772 if (HasBit(itspec->callback_mask, CBM_INDT_AUTOSLOPE)) {
2773 /* If the callback fails, allow autoslope. */
2774 uint16 res = GetIndustryTileCallback(CBID_INDTILE_AUTOSLOPE, 0, 0, gfx, Industry::GetByTile(tile), tile);
2775 if (res == CALLBACK_FAILED || !ConvertBooleanCallback(itspec->grf_prop.grffile, CBID_INDTILE_AUTOSLOPE, res)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
2776 } else {
2777 /* allow autoslope */
2778 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
2782 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
2785 extern const TileTypeProcs _tile_type_industry_procs = {
2786 DrawTile_Industry, // draw_tile_proc
2787 GetSlopePixelZ_Industry, // get_slope_z_proc
2788 ClearTile_Industry, // clear_tile_proc
2789 AddAcceptedCargo_Industry, // add_accepted_cargo_proc
2790 GetTileDesc_Industry, // get_tile_desc_proc
2791 NULL, // get_tile_railway_status_proc
2792 NULL, // get_tile_road_status_proc
2793 NULL, // get_tile_waterway_status_proc
2794 ClickTile_Industry, // click_tile_proc
2795 AnimateTile_Industry, // animate_tile_proc
2796 TileLoop_Industry, // tile_loop_proc
2797 ChangeTileOwner_Industry, // change_tile_owner_proc
2798 NULL, // add_produced_cargo_proc
2799 GetFoundation_Industry, // get_foundation_proc
2800 TerraformTile_Industry, // terraform_tile_proc