Translations update
[openttd/fttd.git] / src / industry_cmd.cpp
blob4ad8d8656a1a0e8b282d73b337cc8fbc4ab0a359
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 "map/bridge.h"
15 #include "industry.h"
16 #include "station_base.h"
17 #include "landscape.h"
18 #include "viewport_func.h"
19 #include "command_func.h"
20 #include "town.h"
21 #include "news_func.h"
22 #include "cheat_type.h"
23 #include "genworld.h"
24 #include "newgrf_cargo.h"
25 #include "newgrf_debug.h"
26 #include "newgrf_industrytiles.h"
27 #include "autoslope.h"
28 #include "water.h"
29 #include "strings_func.h"
30 #include "window_func.h"
31 #include "date_func.h"
32 #include "vehicle_func.h"
33 #include "sound_func.h"
34 #include "animated_tile_func.h"
35 #include "effectvehicle_func.h"
36 #include "effectvehicle_base.h"
37 #include "ai/ai.hpp"
38 #include "core/pool_func.hpp"
39 #include "subsidy_func.h"
40 #include "core/backup_type.hpp"
41 #include "object_base.h"
42 #include "game/game.hpp"
43 #include "station_func.h"
44 #include "error.h"
46 #include "table/strings.h"
47 #include "table/industry_land.h"
48 #include "table/build_industry.h"
50 template<> Industry::Pool Industry::PoolItem::pool ("Industry");
51 INSTANTIATE_POOL_METHODS(Industry)
53 void ShowIndustryViewWindow(int industry);
54 void BuildOilRig(TileIndex tile);
56 static byte _industry_sound_ctr;
57 static TileIndex _industry_sound_tile;
59 uint16 Industry::counts[NUM_INDUSTRYTYPES];
61 IndustrySpec _industry_specs[NUM_INDUSTRYTYPES];
62 IndustryTileSpec _industry_tile_specs[NUM_INDUSTRYTILES];
63 IndustryBuildData _industry_builder; ///< In-game manager of industries.
65 /**
66 * This function initialize the spec arrays of both
67 * industry and industry tiles.
68 * It adjusts the enabling of the industry too, based on climate availability.
69 * This will allow for clearer testings
71 void ResetIndustries()
73 memset(&_industry_specs, 0, sizeof(_industry_specs));
74 memcpy(&_industry_specs, &_origin_industry_specs, sizeof(_origin_industry_specs));
76 /* once performed, enable only the current climate industries */
77 for (IndustryType i = 0; i < NUM_INDUSTRYTYPES; i++) {
78 _industry_specs[i].enabled = i < NEW_INDUSTRYOFFSET &&
79 HasBit(_origin_industry_specs[i].climate_availability, _settings_game.game_creation.landscape);
82 memset(&_industry_tile_specs, 0, sizeof(_industry_tile_specs));
83 memcpy(&_industry_tile_specs, &_origin_industry_tile_specs, sizeof(_origin_industry_tile_specs));
85 /* Reset any overrides that have been set. */
86 _industile_mngr.ResetOverride();
87 _industry_mngr.ResetOverride();
90 /**
91 * Retrieve the type for this industry. Although it is accessed by a tile,
92 * it will return the general type of industry, and not the sprite index
93 * as would do GetIndustryGfx.
94 * @param tile that is queried
95 * @pre IsIndustryTile(tile)
96 * @return general type for this industry, as defined in industry.h
98 IndustryType GetIndustryType(TileIndex tile)
100 assert(IsIndustryTile(tile));
102 const Industry *ind = Industry::GetByTile(tile);
103 assert(ind != NULL);
104 return ind->type;
108 * Accessor for array _industry_specs.
109 * This will ensure at once : proper access and
110 * not allowing modifications of it.
111 * @param thistype of industry (which is the index in _industry_specs)
112 * @pre thistype < NUM_INDUSTRYTYPES
113 * @return a pointer to the corresponding industry spec
115 const IndustrySpec *GetIndustrySpec(IndustryType thistype)
117 assert(thistype < NUM_INDUSTRYTYPES);
118 return &_industry_specs[thistype];
122 * Accessor for array _industry_tile_specs.
123 * This will ensure at once : proper access and
124 * not allowing modifications of it.
125 * @param gfx of industrytile (which is the index in _industry_tile_specs)
126 * @pre gfx < INVALID_INDUSTRYTILE
127 * @return a pointer to the corresponding industrytile spec
129 const IndustryTileSpec *GetIndustryTileSpec(IndustryGfx gfx)
131 assert(gfx < INVALID_INDUSTRYTILE);
132 return &_industry_tile_specs[gfx];
135 Industry::~Industry()
137 if (CleaningPool()) return;
139 /* Industry can also be destroyed when not fully initialized.
140 * This means that we do not have to clear tiles either.
141 * Also we must not decrement industry counts in that case. */
142 if (this->location.w == 0) return;
144 remove_from_tileset();
146 TILE_AREA_LOOP(tile_cur, this->location) {
147 if (IsIndustryTile(tile_cur)) {
148 if (GetIndustryIndex(tile_cur) == this->index) {
149 DeleteNewGRFInspectWindow(GSF_INDUSTRYTILES, tile_cur);
151 /* MakeWaterKeepingClass() can also handle 'land' */
152 MakeWaterKeepingClass(tile_cur, OWNER_NONE);
154 } else if (IsStationTile(tile_cur) && IsOilRig(tile_cur)) {
155 DeleteOilRig(tile_cur);
159 if (GetIndustrySpec(this->type)->behaviour & INDUSTRYBEH_PLANT_FIELDS) {
160 TileArea ta (this->location.tile);
161 ta.expand (21);
163 /* Remove the farmland and convert it to regular tiles over time. */
164 TILE_AREA_LOOP(tile_cur, ta) {
165 if (IsFieldsTile(tile_cur) &&
166 GetIndustryIndexOfField(tile_cur) == this->index) {
167 SetIndustryIndexOfField(tile_cur, INVALID_INDUSTRY);
172 /* don't let any disaster vehicle target invalid industry */
173 ReleaseDisastersTargetingIndustry(this->index);
175 /* Clear the persistent storage. */
176 delete this->psa;
178 DecIndustryTypeCount(this->type);
180 DeleteIndustryNews(this->index);
181 DeleteWindowById(WC_INDUSTRY_VIEW, this->index);
182 DeleteNewGRFInspectWindow(GSF_INDUSTRIES, this->index);
184 DeleteSubsidyWith(ST_INDUSTRY, this->index);
185 CargoPacket::InvalidateAllFrom(ST_INDUSTRY, this->index);
189 * Invalidating some stuff after removing item from the pool.
190 * @param index index of deleted item
192 void Industry::PostDestructor(size_t index)
194 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0);
195 Station::RecomputeIndustriesNearForAll();
200 * Return a random valid industry.
201 * @return random industry, NULL if there are no industries
203 /* static */ Industry *Industry::GetRandom()
205 if (Industry::GetNumItems() == 0) return NULL;
206 int num = RandomRange((uint16)Industry::GetNumItems());
207 size_t index = MAX_UVALUE(size_t);
209 while (num >= 0) {
210 num--;
211 index++;
213 /* Make sure we have a valid industry */
214 while (!Industry::IsValidID(index)) {
215 index++;
216 assert(index < Industry::GetPoolSize());
220 return Industry::Get(index);
224 static void IndustryDrawSugarMine(const TileInfo *ti)
226 if (!IsIndustryCompleted(ti->tile)) return;
228 const DrawIndustryAnimationStruct *d = &_draw_industry_spec1[GetAnimationFrame(ti->tile)];
230 AddChildSpriteScreen (ti->vd, SPR_IT_SUGAR_MINE_SIEVE + d->image_1, PAL_NONE, d->x, 0);
232 if (d->image_2 != 0) {
233 AddChildSpriteScreen (ti->vd, SPR_IT_SUGAR_MINE_CLOUDS + d->image_2 - 1, PAL_NONE, 8, 41);
236 if (d->image_3 != 0) {
237 AddChildSpriteScreen (ti->vd, SPR_IT_SUGAR_MINE_PILE + d->image_3 - 1, PAL_NONE,
238 _drawtile_proc1[d->image_3 - 1].x, _drawtile_proc1[d->image_3 - 1].y);
242 static void IndustryDrawToffeeQuarry(const TileInfo *ti)
244 uint8 x = 0;
246 if (IsIndustryCompleted(ti->tile)) {
247 x = _industry_anim_offs_toffee[GetAnimationFrame(ti->tile)];
248 if (x == 0xFF) {
249 x = 0;
253 AddChildSpriteScreen (ti->vd, SPR_IT_TOFFEE_QUARRY_SHOVEL, PAL_NONE, 22 - x, 24 + x);
254 AddChildSpriteScreen (ti->vd, SPR_IT_TOFFEE_QUARRY_TOFFEE, PAL_NONE, 6, 14);
257 static void IndustryDrawBubbleGenerator( const TileInfo *ti)
259 if (IsIndustryCompleted(ti->tile)) {
260 AddChildSpriteScreen (ti->vd, SPR_IT_BUBBLE_GENERATOR_BUBBLE, PAL_NONE, 5, _industry_anim_offs_bubbles[GetAnimationFrame(ti->tile)]);
262 AddChildSpriteScreen (ti->vd, SPR_IT_BUBBLE_GENERATOR_SPRING, PAL_NONE, 3, 67);
265 static void IndustryDrawToyFactory(const TileInfo *ti)
267 const DrawIndustryAnimationStruct *d = &_industry_anim_offs_toys[GetAnimationFrame(ti->tile)];
269 if (d->image_1 != 0xFF) {
270 AddChildSpriteScreen (ti->vd, SPR_IT_TOY_FACTORY_CLAY, PAL_NONE, d->x, 96 + d->image_1);
273 if (d->image_2 != 0xFF) {
274 AddChildSpriteScreen (ti->vd, SPR_IT_TOY_FACTORY_ROBOT, PAL_NONE, 16 - d->image_2 * 2, 100 + d->image_2);
277 AddChildSpriteScreen (ti->vd, SPR_IT_TOY_FACTORY_STAMP, PAL_NONE, 7, d->image_3);
278 AddChildSpriteScreen (ti->vd, SPR_IT_TOY_FACTORY_STAMP_HOLDER, PAL_NONE, 0, 42);
281 static void IndustryDrawCoalPlantSparks(const TileInfo *ti)
283 if (IsIndustryCompleted(ti->tile)) {
284 uint8 image = GetAnimationFrame(ti->tile);
286 if (image != 0 && image < 7) {
287 AddChildSpriteScreen (ti->vd, image + SPR_IT_POWER_PLANT_TRANSFORMERS,
288 PAL_NONE,
289 _coal_plant_sparks[image - 1].x,
290 _coal_plant_sparks[image - 1].y
296 typedef void IndustryDrawTileProc(const TileInfo *ti);
297 static IndustryDrawTileProc * const _industry_draw_tile_procs[5] = {
298 IndustryDrawSugarMine,
299 IndustryDrawToffeeQuarry,
300 IndustryDrawBubbleGenerator,
301 IndustryDrawToyFactory,
302 IndustryDrawCoalPlantSparks,
305 static void DrawTile_Industry(TileInfo *ti)
307 IndustryGfx gfx = GetIndustryGfx(ti->tile);
308 Industry *ind = Industry::GetByTile(ti->tile);
309 const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
311 /* Retrieve pointer to the draw industry tile struct */
312 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
313 /* Draw the tile using the specialized method of newgrf industrytile.
314 * DrawNewIndustry will return false if ever the resolver could not
315 * find any sprite to display. So in this case, we will jump on the
316 * substitute gfx instead. */
317 if (indts->grf_prop.spritegroup[0] != NULL && DrawNewIndustryTile(ti, ind, gfx, indts)) {
318 return;
319 } else {
320 /* No sprite group (or no valid one) found, meaning no graphics associated.
321 * Use the substitute one instead */
322 if (indts->grf_prop.subst_id != INVALID_INDUSTRYTILE) {
323 gfx = indts->grf_prop.subst_id;
324 /* And point the industrytile spec accordingly */
325 indts = GetIndustryTileSpec(gfx);
330 const DrawBuildingsTileStruct *dits = industry_draw_tile_data[gfx][(indts->anim_state ?
331 GetAnimationFrame(ti->tile) & INDUSTRY_COMPLETED :
332 GetIndustryConstructionStage(ti->tile))];
334 SpriteID image = dits->ground.sprite;
336 /* DrawFoundation() modifies ti->z and ti->tileh */
337 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
339 /* If the ground sprite is the default flat water sprite, draw also canal/river borders.
340 * Do not do this if the tile's WaterClass is 'land'. */
341 if (image == SPR_FLAT_WATER_TILE && IsTileOnWater(ti->tile)) {
342 DrawWaterClassGround(ti);
343 } else {
344 DrawGroundSprite (ti, image, GroundSpritePaletteTransform(image, dits->ground.pal, GENERAL_SPRITE_COLOUR(ind->random_colour)));
347 /* If industries are transparent and invisible, do not draw the upper part */
348 if (IsInvisibilitySet(TO_INDUSTRIES)) return;
350 /* Add industry on top of the ground? */
351 image = dits->building.sprite;
352 if (image != 0) {
353 AddSortableSpriteToDraw (ti->vd, image, SpriteLayoutPaletteTransform(image, dits->building.pal, GENERAL_SPRITE_COLOUR(ind->random_colour)),
354 ti->x + dits->subtile_x,
355 ti->y + dits->subtile_y,
356 dits->width,
357 dits->height,
358 dits->dz,
359 ti->z,
360 IsTransparencySet(TO_INDUSTRIES));
362 if (IsTransparencySet(TO_INDUSTRIES)) return;
366 int proc = dits->draw_proc - 1;
367 if (proc >= 0) _industry_draw_tile_procs[proc](ti);
371 static int GetSlopePixelZ_Industry(TileIndex tile, uint x, uint y)
373 return GetTileMaxPixelZ(tile);
376 static Foundation GetFoundation_Industry(TileIndex tile, Slope tileh)
378 IndustryGfx gfx = GetIndustryGfx(tile);
380 /* For NewGRF industry tiles we might not be drawing a foundation. We need to
381 * account for this, as other structures should
382 * draw the wall of the foundation in this case.
384 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
385 const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
386 if (indts->grf_prop.spritegroup[0] != NULL && HasBit(indts->callback_mask, CBM_INDT_DRAW_FOUNDATIONS)) {
387 uint32 callback_res = GetIndustryTileCallback(CBID_INDTILE_DRAW_FOUNDATIONS, 0, 0, gfx, Industry::GetByTile(tile), tile);
388 if (callback_res != CALLBACK_FAILED && !ConvertBooleanCallback(indts->grf_prop.grffile, CBID_INDTILE_DRAW_FOUNDATIONS, callback_res)) return FOUNDATION_NONE;
391 return FlatteningFoundation(tileh);
394 static void AddAcceptedCargo_Industry(TileIndex tile, CargoArray &acceptance, uint32 *always_accepted)
396 IndustryGfx gfx = GetIndustryGfx(tile);
397 const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
399 /* When we have to use a callback, we put our data in the next two variables */
400 CargoID raw_accepts_cargo[lengthof(itspec->accepts_cargo)];
401 uint8 raw_cargo_acceptance[lengthof(itspec->acceptance)];
403 /* And then these will always point to a same sized array with the required data */
404 const CargoID *accepts_cargo = itspec->accepts_cargo;
405 const uint8 *cargo_acceptance = itspec->acceptance;
407 if (HasBit(itspec->callback_mask, CBM_INDT_ACCEPT_CARGO)) {
408 uint16 res = GetIndustryTileCallback(CBID_INDTILE_ACCEPT_CARGO, 0, 0, gfx, Industry::GetByTile(tile), tile);
409 if (res != CALLBACK_FAILED) {
410 accepts_cargo = raw_accepts_cargo;
411 for (uint i = 0; i < lengthof(itspec->accepts_cargo); i++) raw_accepts_cargo[i] = GetCargoTranslation(GB(res, i * 5, 5), itspec->grf_prop.grffile);
415 if (HasBit(itspec->callback_mask, CBM_INDT_CARGO_ACCEPTANCE)) {
416 uint16 res = GetIndustryTileCallback(CBID_INDTILE_CARGO_ACCEPTANCE, 0, 0, gfx, Industry::GetByTile(tile), tile);
417 if (res != CALLBACK_FAILED) {
418 cargo_acceptance = raw_cargo_acceptance;
419 for (uint i = 0; i < lengthof(itspec->accepts_cargo); i++) raw_cargo_acceptance[i] = GB(res, i * 4, 4);
423 const Industry *ind = Industry::GetByTile(tile);
424 for (byte i = 0; i < lengthof(itspec->accepts_cargo); i++) {
425 CargoID a = accepts_cargo[i];
426 if (a == CT_INVALID || cargo_acceptance[i] == 0) continue; // work only with valid cargoes
428 /* Add accepted cargo */
429 acceptance[a] += cargo_acceptance[i];
431 /* Maybe set 'always accepted' bit (if it's not set already) */
432 if (HasBit(*always_accepted, a)) continue;
434 bool accepts = false;
435 for (uint cargo_index = 0; cargo_index < lengthof(ind->accepts_cargo); cargo_index++) {
436 /* Test whether the industry itself accepts the cargo type */
437 if (ind->accepts_cargo[cargo_index] == a) {
438 accepts = true;
439 break;
443 if (accepts) continue;
445 /* If the industry itself doesn't accept this cargo, set 'always accepted' bit */
446 SetBit(*always_accepted, a);
450 static void GetTileDesc_Industry(TileIndex tile, TileDesc *td)
452 const Industry *i = Industry::GetByTile(tile);
453 const IndustrySpec *is = GetIndustrySpec(i->type);
455 td->owner[0] = i->owner;
456 td->str = is->name;
457 if (!IsIndustryCompleted(tile)) {
458 td->dparam = td->str;
459 td->str = STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION;
462 if (is->grf_prop.grffile != NULL) {
463 td->grf = GetGRFConfig(is->grf_prop.grffile->grfid)->GetName();
467 static CommandCost ClearTile_Industry(TileIndex tile, DoCommandFlag flags)
469 Industry *i = Industry::GetByTile(tile);
470 const IndustrySpec *indspec = GetIndustrySpec(i->type);
472 /* water can destroy industries
473 * in editor you can bulldoze industries
474 * with magic_bulldozer cheat you can destroy industries
475 * (area around OILRIG is water, so water shouldn't flood it
477 if ((_current_company != OWNER_WATER && _game_mode != GM_EDITOR &&
478 !_cheats.magic_bulldozer.value) ||
479 ((flags & DC_AUTO) != 0) ||
480 (_current_company == OWNER_WATER &&
481 ((indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) ||
482 HasBit(GetIndustryTileSpec(GetIndustryGfx(tile))->slopes_refused, 5)))) {
483 SetDParam(1, indspec->name);
484 return_cmd_error(flags & DC_AUTO ? STR_ERROR_GENERIC_OBJECT_IN_THE_WAY : INVALID_STRING_ID);
487 if (flags & DC_EXEC) {
488 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index));
489 Game::NewEvent(new ScriptEventIndustryClose(i->index));
490 delete i;
492 return CommandCost(EXPENSES_CONSTRUCTION, indspec->GetRemovalCost());
495 static void TransportIndustryGoods(TileIndex tile)
497 Industry *i = Industry::GetByTile(tile);
498 const IndustrySpec *indspec = GetIndustrySpec(i->type);
499 bool moved_cargo = false;
501 StationFinder stations(i->location);
503 for (uint j = 0; j < lengthof(i->produced_cargo_waiting); j++) {
504 uint cw = min(i->produced_cargo_waiting[j], 255);
505 if (cw > indspec->minimal_cargo && i->produced_cargo[j] != CT_INVALID) {
506 i->produced_cargo_waiting[j] -= cw;
508 /* fluctuating economy? */
509 if (EconomyIsInRecession()) cw = (cw + 1) / 2;
511 i->this_month_production[j] += cw;
513 uint am = MoveGoodsToStation(i->produced_cargo[j], cw, ST_INDUSTRY, i->index, stations.GetStations());
514 i->this_month_transported[j] += am;
516 moved_cargo |= (am != 0);
520 if (moved_cargo && !StartStopIndustryTileAnimation(i, IAT_INDUSTRY_DISTRIBUTES_CARGO)) {
521 uint newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_production;
523 if (newgfx != INDUSTRYTILE_NOANIM) {
524 ResetIndustryConstructionStage(tile);
525 SetIndustryCompleted(tile);
526 SetIndustryGfx(tile, newgfx);
527 MarkTileDirtyByTile(tile);
533 static void AnimateTile_Industry(TileIndex tile)
535 IndustryGfx gfx = GetIndustryGfx(tile);
537 if (GetIndustryTileSpec(gfx)->animation.status != ANIM_STATUS_NO_ANIMATION) {
538 AnimateNewIndustryTile(tile);
539 return;
542 switch (gfx) {
543 case GFX_SUGAR_MINE_SIEVE:
544 if ((_tick_counter & 1) == 0) {
545 byte m = GetAnimationFrame(tile) + 1;
547 if (_settings_client.sound.ambient) {
548 switch (m & 7) {
549 case 2: SndPlayTileFx(SND_2D_RIP_2, tile); break;
550 case 6: SndPlayTileFx(SND_29_RIP, tile); break;
554 if (m >= 96) {
555 m = 0;
556 DeleteAnimatedTile(tile);
558 SetAnimationFrame(tile, m);
560 MarkTileDirtyByTile(tile);
562 break;
564 case GFX_TOFFEE_QUARY:
565 if ((_tick_counter & 3) == 0) {
566 byte m = GetAnimationFrame(tile);
568 if (_industry_anim_offs_toffee[m] == 0xFF && _settings_client.sound.ambient) {
569 SndPlayTileFx(SND_30_CARTOON_SOUND, tile);
572 if (++m >= 70) {
573 m = 0;
574 DeleteAnimatedTile(tile);
576 SetAnimationFrame(tile, m);
578 MarkTileDirtyByTile(tile);
580 break;
582 case GFX_BUBBLE_CATCHER:
583 if ((_tick_counter & 1) == 0) {
584 byte m = GetAnimationFrame(tile);
586 if (++m >= 40) {
587 m = 0;
588 DeleteAnimatedTile(tile);
590 SetAnimationFrame(tile, m);
592 MarkTileDirtyByTile(tile);
594 break;
596 /* Sparks on a coal plant */
597 case GFX_POWERPLANT_SPARKS:
598 if ((_tick_counter & 3) == 0) {
599 byte m = GetAnimationFrame(tile);
600 if (m == 6) {
601 SetAnimationFrame(tile, 0);
602 DeleteAnimatedTile(tile);
603 } else {
604 SetAnimationFrame(tile, m + 1);
605 MarkTileDirtyByTile(tile);
608 break;
610 case GFX_TOY_FACTORY:
611 if ((_tick_counter & 1) == 0) {
612 byte m = GetAnimationFrame(tile) + 1;
614 switch (m) {
615 case 1: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2C_MACHINERY, tile); break;
616 case 23: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2B_COMEDY_HIT, tile); break;
617 case 28: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2A_EXTRACT_AND_POP, tile); break;
618 default:
619 if (m >= 50) {
620 int n = GetIndustryAnimationLoop(tile) + 1;
621 m = 0;
622 if (n >= 8) {
623 n = 0;
624 DeleteAnimatedTile(tile);
626 SetIndustryAnimationLoop(tile, n);
630 SetAnimationFrame(tile, m);
631 MarkTileDirtyByTile(tile);
633 break;
635 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
636 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
637 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
638 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
639 if ((_tick_counter & 3) == 0) {
640 IndustryGfx gfx = GetIndustryGfx(tile);
642 gfx = (gfx < 155) ? gfx + 1 : 148;
643 SetIndustryGfx(tile, gfx);
644 MarkTileDirtyByTile(tile);
646 break;
648 case GFX_OILWELL_ANIMATED_1:
649 case GFX_OILWELL_ANIMATED_2:
650 case GFX_OILWELL_ANIMATED_3:
651 if ((_tick_counter & 7) == 0) {
652 bool b = Chance16(1, 7);
653 IndustryGfx gfx = GetIndustryGfx(tile);
655 byte m = GetAnimationFrame(tile) + 1;
656 if (m == 4 && (m = 0, ++gfx) == GFX_OILWELL_ANIMATED_3 + 1 && (gfx = GFX_OILWELL_ANIMATED_1, b)) {
657 SetIndustryGfx(tile, GFX_OILWELL_NOT_ANIMATED);
658 SetIndustryConstructionStage(tile, 3);
659 DeleteAnimatedTile(tile);
660 } else {
661 SetAnimationFrame(tile, m);
662 SetIndustryGfx(tile, gfx);
663 MarkTileDirtyByTile(tile);
666 break;
668 case GFX_COAL_MINE_TOWER_ANIMATED:
669 case GFX_COPPER_MINE_TOWER_ANIMATED:
670 case GFX_GOLD_MINE_TOWER_ANIMATED: {
671 int state = _tick_counter & 0x7FF;
673 if ((state -= 0x400) < 0) return;
675 if (state < 0x1A0) {
676 if (state < 0x20 || state >= 0x180) {
677 byte m = GetAnimationFrame(tile);
678 if (!(m & 0x40)) {
679 SetAnimationFrame(tile, m | 0x40);
680 if (_settings_client.sound.ambient) SndPlayTileFx(SND_0B_MINING_MACHINERY, tile);
682 if (state & 7) return;
683 } else {
684 if (state & 3) return;
686 byte m = (GetAnimationFrame(tile) + 1) | 0x40;
687 if (m > 0xC2) m = 0xC0;
688 SetAnimationFrame(tile, m);
689 MarkTileDirtyByTile(tile);
690 } else if (state >= 0x200 && state < 0x3A0) {
691 int i = (state < 0x220 || state >= 0x380) ? 7 : 3;
692 if (state & i) return;
694 byte m = (GetAnimationFrame(tile) & 0xBF) - 1;
695 if (m < 0x80) m = 0x82;
696 SetAnimationFrame(tile, m);
697 MarkTileDirtyByTile(tile);
699 break;
704 static void CreateChimneySmoke(TileIndex tile)
706 uint x = TileX(tile) * TILE_SIZE;
707 uint y = TileY(tile) * TILE_SIZE;
708 int z = GetTileMaxPixelZ(tile);
710 CreateEffectVehicle(x + 15, y + 14, z + 59, EV_CHIMNEY_SMOKE);
713 static void MakeIndustryTileBigger(TileIndex tile)
715 byte cnt = GetIndustryConstructionCounter(tile) + 1;
716 if (cnt != 4) {
717 SetIndustryConstructionCounter(tile, cnt);
718 return;
721 byte stage = GetIndustryConstructionStage(tile) + 1;
722 SetIndustryConstructionCounter(tile, 0);
723 SetIndustryConstructionStage(tile, stage);
724 StartStopIndustryTileAnimation(tile, IAT_CONSTRUCTION_STATE_CHANGE);
725 if (stage == INDUSTRY_COMPLETED) SetIndustryCompleted(tile);
727 MarkTileDirtyByTile(tile);
729 if (!IsIndustryCompleted(tile)) return;
731 IndustryGfx gfx = GetIndustryGfx(tile);
732 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
733 /* New industries are already animated on construction. */
734 return;
737 switch (gfx) {
738 case GFX_POWERPLANT_CHIMNEY:
739 CreateChimneySmoke(tile);
740 break;
742 case GFX_OILRIG_1: {
743 /* Do not require an industry tile to be after the first two GFX_OILRIG_1
744 * tiles (like the default oil rig). Do a proper check to ensure the
745 * tiles belong to the same industry and based on that build the oil rig's
746 * station. */
747 TileIndex other = tile + TileDiffXY(0, 1);
749 if (IsIndustryTile(other) &&
750 GetIndustryGfx(other) == GFX_OILRIG_1 &&
751 GetIndustryIndex(tile) == GetIndustryIndex(other)) {
752 BuildOilRig(tile);
754 break;
757 case GFX_TOY_FACTORY:
758 case GFX_BUBBLE_CATCHER:
759 case GFX_TOFFEE_QUARY:
760 SetAnimationFrame(tile, 0);
761 SetIndustryAnimationLoop(tile, 0);
762 break;
764 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
765 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
766 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
767 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
768 AddAnimatedTile(tile);
769 break;
773 static void TileLoopIndustry_BubbleGenerator(TileIndex tile)
775 static const int8 _bubble_spawn_location[3][4] = {
776 { 11, 0, -4, -14 },
777 { -4, -10, -4, 1 },
778 { 49, 59, 60, 65 },
781 if (_settings_client.sound.ambient) SndPlayTileFx(SND_2E_EXTRACT_AND_POP, tile);
783 int dir = Random() & 3;
785 EffectVehicle *v = CreateEffectVehicleAbove(
786 TileX(tile) * TILE_SIZE + _bubble_spawn_location[0][dir],
787 TileY(tile) * TILE_SIZE + _bubble_spawn_location[1][dir],
788 _bubble_spawn_location[2][dir],
789 EV_BUBBLE
792 if (v != NULL) v->animation_substate = dir;
795 static void TileLoop_Industry(TileIndex tile)
797 if (IsTileOnWater(tile)) TileLoop_Water(tile);
799 /* Normally this doesn't happen, but if an industry NewGRF is removed
800 * an industry that was previously build on water can now be flooded.
801 * If this happens the tile is no longer an industry tile after
802 * returning from TileLoop_Water. */
803 if (!IsIndustryTile(tile)) return;
805 TriggerIndustryTile(tile, INDTILE_TRIGGER_TILE_LOOP);
807 if (!IsIndustryCompleted(tile)) {
808 MakeIndustryTileBigger(tile);
809 return;
812 if (_game_mode == GM_EDITOR) return;
814 TransportIndustryGoods(tile);
816 if (StartStopIndustryTileAnimation(tile, IAT_TILELOOP)) return;
818 IndustryGfx newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_next;
819 if (newgfx != INDUSTRYTILE_NOANIM) {
820 ResetIndustryConstructionStage(tile);
821 SetIndustryGfx(tile, newgfx);
822 MarkTileDirtyByTile(tile);
823 return;
826 IndustryGfx gfx = GetIndustryGfx(tile);
827 switch (gfx) {
828 case GFX_COAL_MINE_TOWER_NOT_ANIMATED:
829 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED:
830 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED:
831 if (!(_tick_counter & 0x400) && Chance16(1, 2)) {
832 switch (gfx) {
833 case GFX_COAL_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COAL_MINE_TOWER_ANIMATED; break;
834 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_ANIMATED; break;
835 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_ANIMATED; break;
837 SetIndustryGfx(tile, gfx);
838 SetAnimationFrame(tile, 0x80);
839 AddAnimatedTile(tile);
841 break;
843 case GFX_OILWELL_NOT_ANIMATED:
844 if (Chance16(1, 6)) {
845 SetIndustryGfx(tile, GFX_OILWELL_ANIMATED_1);
846 SetAnimationFrame(tile, 0);
847 AddAnimatedTile(tile);
849 break;
851 case GFX_COAL_MINE_TOWER_ANIMATED:
852 case GFX_COPPER_MINE_TOWER_ANIMATED:
853 case GFX_GOLD_MINE_TOWER_ANIMATED:
854 if (!(_tick_counter & 0x400)) {
855 switch (gfx) {
856 case GFX_COAL_MINE_TOWER_ANIMATED: gfx = GFX_COAL_MINE_TOWER_NOT_ANIMATED; break;
857 case GFX_COPPER_MINE_TOWER_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_NOT_ANIMATED; break;
858 case GFX_GOLD_MINE_TOWER_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_NOT_ANIMATED; break;
860 SetIndustryGfx(tile, gfx);
861 SetIndustryCompleted(tile);
862 SetIndustryConstructionStage(tile, 3);
863 DeleteAnimatedTile(tile);
865 break;
867 case GFX_POWERPLANT_SPARKS:
868 if (Chance16(1, 3)) {
869 if (_settings_client.sound.ambient) SndPlayTileFx(SND_0C_ELECTRIC_SPARK, tile);
870 AddAnimatedTile(tile);
872 break;
874 case GFX_COPPER_MINE_CHIMNEY:
875 CreateEffectVehicleAbove(TileX(tile) * TILE_SIZE + 6, TileY(tile) * TILE_SIZE + 6, 43, EV_COPPER_MINE_SMOKE);
876 break;
879 case GFX_TOY_FACTORY: {
880 Industry *i = Industry::GetByTile(tile);
881 if (i->was_cargo_delivered) {
882 i->was_cargo_delivered = false;
883 SetIndustryAnimationLoop(tile, 0);
884 AddAnimatedTile(tile);
887 break;
889 case GFX_BUBBLE_GENERATOR:
890 TileLoopIndustry_BubbleGenerator(tile);
891 break;
893 case GFX_TOFFEE_QUARY:
894 AddAnimatedTile(tile);
895 break;
897 case GFX_SUGAR_MINE_SIEVE:
898 if (Chance16(1, 3)) AddAnimatedTile(tile);
899 break;
903 static bool ClickTile_Industry(TileIndex tile)
905 ShowIndustryViewWindow(GetIndustryIndex(tile));
906 return true;
909 static void ChangeTileOwner_Industry(TileIndex tile, Owner old_owner, Owner new_owner)
911 /* If the founder merges, the industry was created by the merged company */
912 Industry *i = Industry::GetByTile(tile);
913 if (i->founder == old_owner) i->founder = (new_owner == INVALID_OWNER) ? OWNER_NONE : new_owner;
917 * Check whether the tile is a forest.
918 * @param tile the tile to investigate.
919 * @return true if and only if the tile is a forest
921 bool IsTileForestIndustry(TileIndex tile)
923 /* Check for industry tile */
924 if (!IsIndustryTile(tile)) return false;
926 const Industry *ind = Industry::GetByTile(tile);
928 /* Check for organic industry (i.e. not processing or extractive) */
929 if ((GetIndustrySpec(ind->type)->life_type & INDUSTRYLIFE_ORGANIC) == 0) return false;
931 /* Check for wood production */
932 for (uint i = 0; i < lengthof(ind->produced_cargo); i++) {
933 /* The industry produces wood. */
934 if (ind->produced_cargo[i] != CT_INVALID && CargoSpec::Get(ind->produced_cargo[i])->label == 'WOOD') return true;
937 return false;
940 static const byte _plantfarmfield_type[] = {1, 1, 1, 1, 1, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6};
942 static bool IsValidFarmFieldTile(TileIndex tile, bool allow_fields)
944 if (!IsGroundTile(tile)) return false;
946 return IsFieldsTile(tile) ? allow_fields :
947 !IsSnowTile(tile) && !IsClearGround(tile, GROUND_DESERT) && !IsClearGround(tile, GROUND_SHORE);
950 static void SetupFarmFieldFence(TileIndex tile, int size, byte type, DiagDirection side)
952 TileIndexDiff diff = (DiagDirToAxis(side) == AXIS_Y ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
954 do {
955 tile = TILE_MASK(tile);
957 if (IsFieldsTile(tile)) {
958 byte or_ = type;
960 if (or_ == 1 && Chance16(1, 7)) or_ = 2;
962 SetFence(tile, side, or_);
965 tile += diff;
966 } while (--size);
969 static void PlantFarmField(TileIndex tile, IndustryID industry)
971 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
972 if (GetTileZ(tile) + 2 >= GetSnowLine()) return;
975 /* determine field size */
976 uint32 r = (Random() & 0x303) + 0x404;
977 if (_settings_game.game_creation.landscape == LT_ARCTIC) r += 0x404;
978 uint size_x = GB(r, 0, 8);
979 uint size_y = GB(r, 8, 8);
981 TileArea ta (tile);
982 ta.expand (size_x / 2, size_y / 2, size_x - (size_x / 2), size_y - (size_y / 2));
984 if (ta.w == 0 || ta.h == 0) return;
986 /* check the amount of bad tiles */
987 int count = 0;
988 TILE_AREA_LOOP(cur_tile, ta) {
989 assert(cur_tile < MapSize());
990 count += IsValidFarmFieldTile(cur_tile, false);
992 if (count * 2 < ta.w * ta.h) return;
994 /* determine type of field */
995 r = Random();
996 uint counter = GB(r, 5, 3);
997 uint field_type = GB(r, 8, 8) * 9 >> 8;
999 /* make field */
1000 TILE_AREA_LOOP(cur_tile, ta) {
1001 assert(cur_tile < MapSize());
1002 if (IsValidFarmFieldTile(cur_tile, true)) {
1003 MakeField(cur_tile, field_type, industry);
1004 SetClearCounter(cur_tile, counter);
1005 MarkTileDirtyByTile(cur_tile);
1009 int type = 3;
1010 if (_settings_game.game_creation.landscape != LT_ARCTIC && _settings_game.game_creation.landscape != LT_TROPIC) {
1011 type = _plantfarmfield_type[Random() & 0xF];
1014 SetupFarmFieldFence(ta.tile, ta.h, type, DIAGDIR_NE);
1015 SetupFarmFieldFence(ta.tile, ta.w, type, DIAGDIR_NW);
1016 SetupFarmFieldFence(ta.tile + TileDiffXY(ta.w - 1, 0), ta.h, type, DIAGDIR_SW);
1017 SetupFarmFieldFence(ta.tile + TileDiffXY(0, ta.h - 1), ta.w, type, DIAGDIR_SE);
1020 void PlantRandomFarmField(const Industry *i)
1022 int x = i->location.w / 2 + Random() % 31 - 16;
1023 int y = i->location.h / 2 + Random() % 31 - 16;
1025 TileIndex tile = TileAddWrap(i->location.tile, x, y);
1027 if (tile != INVALID_TILE) PlantFarmField(tile, i->index);
1031 * Perform a circular search around the Lumber Mill in order to find trees to cut
1032 * @param i industry
1034 static void ChopLumberMillTrees(Industry *i)
1036 /* We only want to cut trees if all tiles are completed. */
1037 TILE_AREA_LOOP(tile_cur, i->location) {
1038 if (i->TileBelongsToIndustry(tile_cur)) {
1039 if (!IsIndustryCompleted(tile_cur)) return;
1043 TileIndex tile = i->location.tile;
1044 CircularTileIterator iter (tile, 40); // 40x40 tiles to search
1045 for (tile = iter; tile != INVALID_TILE; tile = ++iter) {
1046 if (IsTreeTile(tile) && GetTreeGrowth(tile) > 2) { ///< 3 and up means all fully grown trees
1047 /* found a tree */
1049 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
1051 _industry_sound_ctr = 1;
1052 _industry_sound_tile = tile;
1053 if (_settings_client.sound.ambient) SndPlayTileFx(SND_38_CHAINSAW, tile);
1055 DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
1057 cur_company.Restore();
1058 i->produced_cargo_waiting[0] = min(0xffff, i->produced_cargo_waiting[0] + 45); // Found a tree, add according value to waiting cargo.
1059 break;
1064 static void ProduceIndustryGoods(Industry *i)
1066 const IndustrySpec *indsp = GetIndustrySpec(i->type);
1068 /* play a sound? */
1069 if ((i->counter & 0x3F) == 0) {
1070 uint32 r;
1071 uint num;
1072 if (Chance16R(1, 14, r) && (num = indsp->number_of_sounds) != 0 && _settings_client.sound.ambient) {
1073 SndPlayTileFx(
1074 (SoundFx)(indsp->random_sounds[((r >> 16) * num) >> 16]),
1075 i->location.tile);
1079 i->counter--;
1081 /* produce some cargo */
1082 if ((i->counter % INDUSTRY_PRODUCE_TICKS) == 0) {
1083 if (HasBit(indsp->callback_mask, CBM_IND_PRODUCTION_256_TICKS)) IndustryProductionCallback(i, 1);
1085 IndustryBehaviour indbehav = indsp->behaviour;
1086 i->produced_cargo_waiting[0] = min(0xffff, i->produced_cargo_waiting[0] + i->production_rate[0]);
1087 i->produced_cargo_waiting[1] = min(0xffff, i->produced_cargo_waiting[1] + i->production_rate[1]);
1089 if ((indbehav & INDUSTRYBEH_PLANT_FIELDS) != 0) {
1090 uint16 cb_res = CALLBACK_FAILED;
1091 if (HasBit(indsp->callback_mask, CBM_IND_SPECIAL_EFFECT)) {
1092 cb_res = GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 0, i, i->type, i->location.tile);
1095 bool plant;
1096 if (cb_res != CALLBACK_FAILED) {
1097 plant = ConvertBooleanCallback(indsp->grf_prop.grffile, CBID_INDUSTRY_SPECIAL_EFFECT, cb_res);
1098 } else {
1099 plant = Chance16(1, 8);
1102 if (plant) PlantRandomFarmField(i);
1104 if ((indbehav & INDUSTRYBEH_CUT_TREES) != 0) {
1105 uint16 cb_res = CALLBACK_FAILED;
1106 if (HasBit(indsp->callback_mask, CBM_IND_SPECIAL_EFFECT)) {
1107 cb_res = GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 1, i, i->type, i->location.tile);
1110 bool cut;
1111 if (cb_res != CALLBACK_FAILED) {
1112 cut = ConvertBooleanCallback(indsp->grf_prop.grffile, CBID_INDUSTRY_SPECIAL_EFFECT, cb_res);
1113 } else {
1114 cut = ((i->counter % INDUSTRY_CUT_TREE_TICKS) == 0);
1117 if (cut) ChopLumberMillTrees(i);
1120 TriggerIndustry(i, INDUSTRY_TRIGGER_INDUSTRY_TICK);
1121 StartStopIndustryTileAnimation(i, IAT_INDUSTRY_TICK);
1125 void OnTick_Industry()
1127 if (_industry_sound_ctr != 0) {
1128 _industry_sound_ctr++;
1130 if (_industry_sound_ctr == 75) {
1131 if (_settings_client.sound.ambient) SndPlayTileFx(SND_37_BALLOON_SQUEAK, _industry_sound_tile);
1132 } else if (_industry_sound_ctr == 160) {
1133 _industry_sound_ctr = 0;
1134 if (_settings_client.sound.ambient) SndPlayTileFx(SND_36_CARTOON_CRASH, _industry_sound_tile);
1138 if (_game_mode == GM_EDITOR) return;
1140 Industry *i;
1141 FOR_ALL_INDUSTRIES(i) {
1142 ProduceIndustryGoods(i);
1147 * Check the conditions of #CHECK_NOTHING (Always succeeds).
1148 * @param tile %Tile to perform the checking.
1149 * @return Succeeded or failed command.
1151 static CommandCost CheckNewIndustry_NULL(TileIndex tile)
1153 return CommandCost();
1157 * Check the conditions of #CHECK_FOREST (Industry should be build above snow-line in arctic climate).
1158 * @param tile %Tile to perform the checking.
1159 * @return Succeeded or failed command.
1161 static CommandCost CheckNewIndustry_Forest(TileIndex tile)
1163 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
1164 if (GetTileZ(tile) < HighestSnowLine() + 2) {
1165 return_cmd_error(STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED);
1168 return CommandCost();
1172 * Check the conditions of #CHECK_REFINERY (Industry should be positioned near edge of the map).
1173 * @param tile %Tile to perform the checking.
1174 * @return Succeeded or failed command.
1176 static CommandCost CheckNewIndustry_OilRefinery(TileIndex tile)
1178 if (_game_mode == GM_EDITOR) return CommandCost();
1179 if (DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _settings_game.game_creation.oil_refinery_limit) return CommandCost();
1181 return_cmd_error(STR_ERROR_CAN_ONLY_BE_POSITIONED);
1184 extern bool _ignore_restrictions;
1187 * Check the conditions of #CHECK_OIL_RIG (Industries at sea should be positioned near edge of the map).
1188 * @param tile %Tile to perform the checking.
1189 * @return Succeeded or failed command.
1191 static CommandCost CheckNewIndustry_OilRig(TileIndex tile)
1193 if (_game_mode == GM_EDITOR && _ignore_restrictions) return CommandCost();
1194 if (TileHeight(tile) == 0 &&
1195 DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _settings_game.game_creation.oil_refinery_limit) return CommandCost();
1197 return_cmd_error(STR_ERROR_CAN_ONLY_BE_POSITIONED);
1201 * Check the conditions of #CHECK_FARM (Industry should be below snow-line in arctic).
1202 * @param tile %Tile to perform the checking.
1203 * @return Succeeded or failed command.
1205 static CommandCost CheckNewIndustry_Farm(TileIndex tile)
1207 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
1208 if (GetTileZ(tile) + 2 >= HighestSnowLine()) {
1209 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1212 return CommandCost();
1216 * Check the conditions of #CHECK_PLANTATION (Industry should NOT be in the desert).
1217 * @param tile %Tile to perform the checking.
1218 * @return Succeeded or failed command.
1220 static CommandCost CheckNewIndustry_Plantation(TileIndex tile)
1222 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
1223 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1225 return CommandCost();
1229 * Check the conditions of #CHECK_WATER (Industry should be in the desert).
1230 * @param tile %Tile to perform the checking.
1231 * @return Succeeded or failed command.
1233 static CommandCost CheckNewIndustry_Water(TileIndex tile)
1235 if (GetTropicZone(tile) != TROPICZONE_DESERT) {
1236 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT);
1238 return CommandCost();
1242 * Check the conditions of #CHECK_LUMBERMILL (Industry should be in the rain forest).
1243 * @param tile %Tile to perform the checking.
1244 * @return Succeeded or failed command.
1246 static CommandCost CheckNewIndustry_Lumbermill(TileIndex tile)
1248 if (GetTropicZone(tile) != TROPICZONE_RAINFOREST) {
1249 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST);
1251 return CommandCost();
1255 * Check the conditions of #CHECK_BUBBLEGEN (Industry should be in low land).
1256 * @param tile %Tile to perform the checking.
1257 * @return Succeeded or failed command.
1259 static CommandCost CheckNewIndustry_BubbleGen(TileIndex tile)
1261 if (GetTileZ(tile) > 4) {
1262 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS);
1264 return CommandCost();
1268 * Industrytype check function signature.
1269 * @param tile %Tile to check.
1270 * @return Succeeded or failed command.
1272 typedef CommandCost CheckNewIndustryProc(TileIndex tile);
1274 /** Check functions for different types of industry. */
1275 static CheckNewIndustryProc * const _check_new_industry_procs[CHECK_END] = {
1276 CheckNewIndustry_NULL, ///< CHECK_NOTHING
1277 CheckNewIndustry_Forest, ///< CHECK_FOREST
1278 CheckNewIndustry_OilRefinery, ///< CHECK_REFINERY
1279 CheckNewIndustry_Farm, ///< CHECK_FARM
1280 CheckNewIndustry_Plantation, ///< CHECK_PLANTATION
1281 CheckNewIndustry_Water, ///< CHECK_WATER
1282 CheckNewIndustry_Lumbermill, ///< CHECK_LUMBERMILL
1283 CheckNewIndustry_BubbleGen, ///< CHECK_BUBBLEGEN
1284 CheckNewIndustry_OilRig, ///< CHECK_OIL_RIG
1288 * Find a town for the industry, while checking for multiple industries in the same town.
1289 * @param tile Position of the industry to build.
1290 * @param type Industry type.
1291 * @param [out] town Pointer to return town for the new industry, \c NULL is written if no good town can be found.
1292 * @return Succeeded or failed command.
1294 * @pre \c *t != NULL
1295 * @post \c *t points to a town on success, and \c NULL on failure.
1297 static CommandCost FindTownForIndustry(TileIndex tile, int type, Town **t)
1299 *t = ClosestTownFromTile(tile);
1301 if (_settings_game.economy.multiple_industry_per_town) return CommandCost();
1303 const Industry *i;
1304 FOR_ALL_INDUSTRIES(i) {
1305 if (i->type == (byte)type && i->town == *t) {
1306 *t = NULL;
1307 return_cmd_error(STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN);
1311 return CommandCost();
1314 bool IsSlopeRefused(Slope current, Slope refused)
1316 if (IsSteepSlope(current)) return true;
1317 if (current != SLOPE_FLAT) {
1318 if (IsSteepSlope(refused)) return true;
1320 Slope t = ComplementSlope(current);
1322 if ((refused & SLOPE_W) && (t & SLOPE_NW)) return true;
1323 if ((refused & SLOPE_S) && (t & SLOPE_NE)) return true;
1324 if ((refused & SLOPE_E) && (t & SLOPE_SW)) return true;
1325 if ((refused & SLOPE_N) && (t & SLOPE_SE)) return true;
1328 return false;
1332 * Are the tiles of the industry free?
1333 * @param tile Position to check.
1334 * @param it Industry tiles table.
1335 * @param itspec_index The index of the itsepc to build/fund
1336 * @param type Type of the industry.
1337 * @param initial_random_bits The random bits the industry is going to have after construction.
1338 * @param founder Industry founder
1339 * @param creation_type The circumstances the industry is created under.
1340 * @param [out] custom_shape_check Perform custom check for the site.
1341 * @return Failed or succeeded command.
1343 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)
1345 bool refused_slope = false;
1346 bool custom_shape = false;
1348 do {
1349 IndustryGfx gfx = GetTranslatedIndustryTileID(it->gfx);
1350 TileIndex cur_tile = TileAddWrap(tile, it->ti.x, it->ti.y);
1352 if (!IsValidTile(cur_tile)) {
1353 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1356 if (gfx == GFX_WATERTILE_SPECIALCHECK) {
1357 if (!IsPlainWaterTile(cur_tile) ||
1358 !IsTileFlat(cur_tile)) {
1359 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1361 } else {
1362 CommandCost ret = EnsureNoVehicleOnGround(cur_tile);
1363 if (ret.Failed()) return ret;
1364 if (HasBridgeAbove(cur_tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1366 const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
1368 IndustryBehaviour ind_behav = GetIndustrySpec(type)->behaviour;
1370 /* Perform land/water check if not disabled */
1371 if (!HasBit(its->slopes_refused, 5) && ((HasTileWaterClass(cur_tile) && IsTileOnWater(cur_tile)) == !(ind_behav & INDUSTRYBEH_BUILT_ONWATER))) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1373 if (HasBit(its->callback_mask, CBM_INDT_SHAPE_CHECK)) {
1374 custom_shape = true;
1375 CommandCost ret = PerformIndustryTileSlopeCheck(tile, cur_tile, its, type, gfx, itspec_index, initial_random_bits, founder, creation_type);
1376 if (ret.Failed()) return ret;
1377 } else {
1378 Slope tileh = GetTileSlope(cur_tile);
1379 refused_slope |= IsSlopeRefused(tileh, its->slopes_refused);
1382 if ((ind_behav & (INDUSTRYBEH_ONLY_INTOWN | INDUSTRYBEH_TOWN1200_MORE)) || // Tile must be a house
1383 ((ind_behav & INDUSTRYBEH_ONLY_NEARTOWN) && IsHouseTile(cur_tile))) { // Tile is allowed to be a house (and it is a house)
1384 if (!IsHouseTile(cur_tile)) {
1385 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS);
1388 /* Clear the tiles as OWNER_TOWN to not affect town rating, and to not clear protected buildings */
1389 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
1390 CommandCost ret = DoCommand(cur_tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR);
1391 cur_company.Restore();
1393 if (ret.Failed()) return ret;
1394 } else {
1395 /* Clear the tiles, but do not affect town ratings */
1396 CommandCost ret = DoCommand(cur_tile, 0, 0, DC_AUTO | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR);
1398 if (ret.Failed()) return ret;
1401 } while ((++it)->ti.x != -0x80);
1403 if (custom_shape_check != NULL) *custom_shape_check = custom_shape;
1405 /* It is almost impossible to have a fully flat land in TG, so what we
1406 * do is that we check if we can make the land flat later on. See
1407 * CheckIfCanLevelIndustryPlatform(). */
1408 if (!refused_slope || (_settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world && !custom_shape && !_ignore_restrictions)) {
1409 return CommandCost();
1411 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1415 * Is the industry allowed to be built at this place for the town?
1416 * @param tile Tile to construct the industry.
1417 * @param type Type of the industry.
1418 * @param t Town authority that the industry belongs to.
1419 * @return Succeeded or failed command.
1421 static CommandCost CheckIfIndustryIsAllowed(TileIndex tile, int type, const Town *t)
1423 if ((GetIndustrySpec(type)->behaviour & INDUSTRYBEH_TOWN1200_MORE) && t->cache.population < 1200) {
1424 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200);
1427 if ((GetIndustrySpec(type)->behaviour & INDUSTRYBEH_ONLY_NEARTOWN) && DistanceMax(t->xy, tile) > 9) {
1428 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER);
1431 return CommandCost();
1434 static bool CheckCanTerraformSurroundingTiles(TileIndex tile, uint height, int internal)
1436 /* Check if we don't leave the map */
1437 if (TileX(tile) == 0 || TileY(tile) == 0 || IsVoidTile(tile)) return false;
1439 TileArea ta(tile - TileDiffXY(1, 1), 2, 2);
1440 TILE_AREA_LOOP(tile_walk, ta) {
1441 uint curh = TileHeight(tile_walk);
1442 /* Is the tile clear? */
1443 if (!IsGroundTile(tile_walk)) return false;
1445 /* Don't allow too big of a change if this is the sub-tile check */
1446 if (internal != 0 && Delta(curh, height) > 1) return false;
1448 /* Different height, so the surrounding tiles of this tile
1449 * has to be correct too (in level, or almost in level)
1450 * else you get a chain-reaction of terraforming. */
1451 if (internal == 0 && curh != height) {
1452 if (TileX(tile_walk) == 0 || TileY(tile_walk) == 0 || !CheckCanTerraformSurroundingTiles(tile_walk + TileDiffXY(-1, -1), height, internal + 1)) {
1453 return false;
1458 return true;
1462 * This function tries to flatten out the land below an industry, without
1463 * damaging the surroundings too much.
1465 static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, DoCommandFlag flags, const IndustryTileTable *it, int type)
1467 const int MKEND = -0x80; // used for last element in an IndustryTileTable (see build_industry.h)
1468 int max_x = 0;
1469 int max_y = 0;
1471 /* Finds dimensions of largest variant of this industry */
1472 do {
1473 if (it->gfx == 0xFF) continue; // FF been a marquer for a check on clear water, skip it
1474 if (it->ti.x > max_x) max_x = it->ti.x;
1475 if (it->ti.y > max_y) max_y = it->ti.y;
1476 } while ((++it)->ti.x != MKEND);
1478 /* Remember level height */
1479 uint h = TileHeight(tile);
1481 if (TileX(tile) <= _settings_game.construction.industry_platform + 1U || TileY(tile) <= _settings_game.construction.industry_platform + 1U) return false;
1482 /* Check that all tiles in area and surrounding are clear
1483 * this determines that there are no obstructing items */
1485 TileArea ta(tile + TileDiffXY(-_settings_game.construction.industry_platform, -_settings_game.construction.industry_platform),
1486 max_x + 2 + 2 * _settings_game.construction.industry_platform, max_y + 2 + 2 * _settings_game.construction.industry_platform);
1488 if (TileX(ta.tile) + ta.w >= MapMaxX() || TileY(ta.tile) + ta.h >= MapMaxY()) return false;
1490 /* _current_company is OWNER_NONE for randomly generated industries and in editor, or the company who funded or prospected the industry.
1491 * Perform terraforming as OWNER_TOWN to disable autoslope and town ratings. */
1492 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
1494 TILE_AREA_LOOP(tile_walk, ta) {
1495 uint curh = TileHeight(tile_walk);
1496 if (curh != h) {
1497 /* This tile needs terraforming. Check if we can do that without
1498 * damaging the surroundings too much. */
1499 if (!CheckCanTerraformSurroundingTiles(tile_walk, h, 0)) {
1500 cur_company.Restore();
1501 return false;
1503 /* This is not 100% correct check, but the best we can do without modifying the map.
1504 * What is missing, is if the difference in height is more than 1.. */
1505 if (DoCommand(tile_walk, SLOPE_N, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND).Failed()) {
1506 cur_company.Restore();
1507 return false;
1512 if (flags & DC_EXEC) {
1513 /* Terraform the land under the industry */
1514 TILE_AREA_LOOP(tile_walk, ta) {
1515 uint curh = TileHeight(tile_walk);
1516 while (curh != h) {
1517 /* We give the terraforming for free here, because we can't calculate
1518 * exact cost in the test-round, and as we all know, that will cause
1519 * a nice assert if they don't match ;) */
1520 DoCommand(tile_walk, SLOPE_N, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND);
1521 curh += (curh > h) ? -1 : 1;
1526 cur_company.Restore();
1527 return true;
1532 * Check that the new industry is far enough from conflicting industries.
1533 * @param tile Tile to construct the industry.
1534 * @param type Type of the new industry.
1535 * @return Succeeded or failed command.
1537 static CommandCost CheckIfFarEnoughFromConflictingIndustry(TileIndex tile, int type)
1539 const IndustrySpec *indspec = GetIndustrySpec(type);
1541 for (Industry::TileSet::Iterator iter (&Industry::set, tile, 14); iter.get_item() != NULL; iter.next()) {
1542 const Industry *i = iter.get_item();
1544 /* Within 14 tiles from another industry is considered close */
1545 if (DistanceMax(tile, i->location.tile) > 14) continue;
1547 /* check if there are any conflicting industry types around */
1548 if (i->type == indspec->conflicting[0] ||
1549 i->type == indspec->conflicting[1] ||
1550 i->type == indspec->conflicting[2]) {
1551 return_cmd_error(STR_ERROR_INDUSTRY_TOO_CLOSE);
1554 return CommandCost();
1558 * Advertise about a new industry opening.
1559 * @param ind Industry being opened.
1561 static void AdvertiseIndustryOpening(const Industry *ind)
1563 const IndustrySpec *ind_spc = GetIndustrySpec(ind->type);
1564 AddNewsItem<IndustryNewsItem> (ind_spc->new_industry_text,
1565 NT_INDUSTRY_OPEN, ind->index,
1566 ind_spc->name,
1567 ind_spc->new_industry_text > STR_LAST_STRINGID ?
1568 STR_TOWN_NAME : ind->town->index,
1569 ind->town->index);
1570 AI::BroadcastNewEvent(new ScriptEventIndustryOpen(ind->index));
1571 Game::NewEvent(new ScriptEventIndustryOpen(ind->index));
1575 * Put an industry on the map.
1576 * @param i Just allocated poolitem, mostly empty.
1577 * @param tile North tile of the industry.
1578 * @param type Type of the industry.
1579 * @param it Industrylayout to build.
1580 * @param layout Number of the layout.
1581 * @param t Nearest town.
1582 * @param founder Founder of the industry; OWNER_NONE in case of random construction.
1583 * @param initial_random_bits Random bits for the industry.
1585 static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, const IndustryTileTable *it, byte layout, Town *t, Owner founder, uint16 initial_random_bits)
1587 const IndustrySpec *indspec = GetIndustrySpec(type);
1589 i->location = TileArea(tile, 1, 1);
1590 i->type = type;
1591 Industry::IncIndustryTypeCount(type);
1593 i->produced_cargo[0] = indspec->produced_cargo[0];
1594 i->produced_cargo[1] = indspec->produced_cargo[1];
1595 i->accepts_cargo[0] = indspec->accepts_cargo[0];
1596 i->accepts_cargo[1] = indspec->accepts_cargo[1];
1597 i->accepts_cargo[2] = indspec->accepts_cargo[2];
1598 i->production_rate[0] = indspec->production_rate[0];
1599 i->production_rate[1] = indspec->production_rate[1];
1601 /* don't use smooth economy for industries using production related callbacks */
1602 if (indspec->UsesSmoothEconomy()) {
1603 i->production_rate[0] = min((RandomRange(256) + 128) * i->production_rate[0] >> 8, 255);
1604 i->production_rate[1] = min((RandomRange(256) + 128) * i->production_rate[1] >> 8, 255);
1607 i->town = t;
1608 i->owner = OWNER_NONE;
1610 uint16 r = Random();
1611 i->random_colour = GB(r, 0, 4);
1612 i->counter = GB(r, 4, 12);
1613 i->random = initial_random_bits;
1614 i->produced_cargo_waiting[0] = 0;
1615 i->produced_cargo_waiting[1] = 0;
1616 i->incoming_cargo_waiting[0] = 0;
1617 i->incoming_cargo_waiting[1] = 0;
1618 i->incoming_cargo_waiting[2] = 0;
1619 i->this_month_production[0] = 0;
1620 i->this_month_production[1] = 0;
1621 i->this_month_transported[0] = 0;
1622 i->this_month_transported[1] = 0;
1623 i->last_month_pct_transported[0] = 0;
1624 i->last_month_pct_transported[1] = 0;
1625 i->last_month_transported[0] = 0;
1626 i->last_month_transported[1] = 0;
1627 i->was_cargo_delivered = false;
1628 i->last_prod_year = _cur_year;
1629 i->founder = founder;
1631 i->construction_date = _date;
1632 i->construction_type = (_game_mode == GM_EDITOR) ? ICT_SCENARIO_EDITOR :
1633 (_generating_world ? ICT_MAP_GENERATION : ICT_NORMAL_GAMEPLAY);
1635 /* Adding 1 here makes it conform to specs of var44 of varaction2 for industries
1636 * 0 = created prior of newindustries
1637 * else, chosen layout + 1 */
1638 i->selected_layout = layout + 1;
1640 i->prod_level = PRODLEVEL_DEFAULT;
1642 /* Call callbacks after the regular fields got initialised. */
1644 if (HasBit(indspec->callback_mask, CBM_IND_PROD_CHANGE_BUILD)) {
1645 uint16 res = GetIndustryCallback(CBID_INDUSTRY_PROD_CHANGE_BUILD, 0, Random(), i, type, INVALID_TILE);
1646 if (res != CALLBACK_FAILED) {
1647 if (res < PRODLEVEL_MINIMUM || res > PRODLEVEL_MAXIMUM) {
1648 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_PROD_CHANGE_BUILD, res);
1649 } else {
1650 i->prod_level = res;
1651 i->RecomputeProductionMultipliers();
1656 if (_generating_world) {
1657 i->last_month_production[0] = i->production_rate[0] * 8;
1658 i->last_month_production[1] = i->production_rate[1] * 8;
1659 } else {
1660 i->last_month_production[0] = i->last_month_production[1] = 0;
1663 if (HasBit(indspec->callback_mask, CBM_IND_DECIDE_COLOUR)) {
1664 uint16 res = GetIndustryCallback(CBID_INDUSTRY_DECIDE_COLOUR, 0, 0, i, type, INVALID_TILE);
1665 if (res != CALLBACK_FAILED) {
1666 if (GB(res, 4, 11) != 0) ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_DECIDE_COLOUR, res);
1667 i->random_colour = GB(res, 0, 4);
1671 if (HasBit(indspec->callback_mask, CBM_IND_INPUT_CARGO_TYPES)) {
1672 for (uint j = 0; j < lengthof(i->accepts_cargo); j++) i->accepts_cargo[j] = CT_INVALID;
1673 for (uint j = 0; j < lengthof(i->accepts_cargo); j++) {
1674 uint16 res = GetIndustryCallback(CBID_INDUSTRY_INPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE);
1675 if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
1676 if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
1677 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_INPUT_CARGO_TYPES, res);
1678 break;
1680 i->accepts_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
1684 if (HasBit(indspec->callback_mask, CBM_IND_OUTPUT_CARGO_TYPES)) {
1685 for (uint j = 0; j < lengthof(i->produced_cargo); j++) i->produced_cargo[j] = CT_INVALID;
1686 for (uint j = 0; j < lengthof(i->produced_cargo); j++) {
1687 uint16 res = GetIndustryCallback(CBID_INDUSTRY_OUTPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE);
1688 if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
1689 if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
1690 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_OUTPUT_CARGO_TYPES, res);
1691 break;
1693 i->produced_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
1697 /* Plant the tiles */
1699 do {
1700 TileIndex cur_tile = tile + ToTileIndexDiff(it->ti);
1702 if (it->gfx != GFX_WATERTILE_SPECIALCHECK) {
1703 i->location.Add(cur_tile);
1705 WaterClass wc = (IsPlainWaterTile(cur_tile) ? GetWaterClass(cur_tile) : WATER_CLASS_INVALID);
1707 DoCommand(cur_tile, 0, 0, DC_EXEC | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR);
1709 MakeIndustry(cur_tile, i->index, it->gfx, Random(), wc);
1711 if (_generating_world) {
1712 SetIndustryConstructionCounter(cur_tile, 3);
1713 SetIndustryConstructionStage(cur_tile, 2);
1716 /* it->gfx is stored in the map. But the translated ID cur_gfx is the interesting one */
1717 IndustryGfx cur_gfx = GetTranslatedIndustryTileID(it->gfx);
1718 const IndustryTileSpec *its = GetIndustryTileSpec(cur_gfx);
1719 if (its->animation.status != ANIM_STATUS_NO_ANIMATION) AddAnimatedTile(cur_tile);
1721 } while ((++it)->ti.x != -0x80);
1723 if (GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_PLANT_ON_BUILT) {
1724 for (uint j = 0; j != 50; j++) PlantRandomFarmField(i);
1726 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0);
1728 Station::RecomputeIndustriesNearForAll();
1732 * Helper function for Build/Fund an industry
1733 * @param tile tile where industry is built
1734 * @param type of industry to build
1735 * @param flags of operations to conduct
1736 * @param indspec pointer to industry specifications
1737 * @param itspec_index the index of the itsepc to build/fund
1738 * @param seed random seed (possibly) used by industries
1739 * @param initial_random_bits The random bits the industry is going to have after construction.
1740 * @param founder Founder of the industry
1741 * @param creation_type The circumstances the industry is created under.
1742 * @param [out] ip Pointer to store newly created industry.
1743 * @return Succeeded or failed command.
1745 * @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.
1747 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)
1749 assert(itspec_index < indspec->num_table);
1750 const IndustryTileTable *it = indspec->table[itspec_index];
1751 bool custom_shape_check = false;
1753 *ip = NULL;
1755 SmallVector<ClearedObjectArea, 1> object_areas(_cleared_object_areas);
1756 CommandCost ret = CheckIfIndustryTilesAreFree(tile, it, itspec_index, type, random_initial_bits, founder, creation_type, &custom_shape_check);
1757 _cleared_object_areas = object_areas;
1758 if (ret.Failed()) return ret;
1760 if (HasBit(GetIndustrySpec(type)->callback_mask, CBM_IND_LOCATION)) {
1761 ret = CheckIfCallBackAllowsCreation(tile, type, itspec_index, random_var8f, random_initial_bits, founder, creation_type);
1762 } else {
1763 ret = _check_new_industry_procs[indspec->check_proc](tile);
1765 if (ret.Failed()) return ret;
1767 if (!custom_shape_check && _settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world &&
1768 !_ignore_restrictions && !CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER, it, type)) {
1769 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1772 ret = CheckIfFarEnoughFromConflictingIndustry(tile, type);
1773 if (ret.Failed()) return ret;
1775 Town *t = NULL;
1776 ret = FindTownForIndustry(tile, type, &t);
1777 if (ret.Failed()) return ret;
1778 assert(t != NULL);
1780 ret = CheckIfIndustryIsAllowed(tile, type, t);
1781 if (ret.Failed()) return ret;
1783 if (!Industry::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_INDUSTRIES);
1785 if (flags & DC_EXEC) {
1786 *ip = new Industry(tile);
1787 if (!custom_shape_check) CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER | DC_EXEC, it, type);
1788 DoCreateNewIndustry(*ip, tile, type, it, itspec_index, t, founder, random_initial_bits);
1791 return CommandCost();
1795 * Build/Fund an industry
1796 * @param tile tile where industry is built
1797 * @param flags of operations to conduct
1798 * @param p1 various bitstuffed elements
1799 * - p1 = (bit 0 - 7) - industry type see build_industry.h and see industry.h
1800 * - p1 = (bit 8 - 15) - first layout to try
1801 * - p1 = (bit 16 ) - 0 = prospect, 1 = fund (only valid if current company is DEITY)
1802 * @param p2 seed to use for desyncfree randomisations
1803 * @param text unused
1804 * @return the cost of this operation or an error
1806 CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1808 IndustryType it = GB(p1, 0, 8);
1809 if (it >= NUM_INDUSTRYTYPES) return CMD_ERROR;
1811 const IndustrySpec *indspec = GetIndustrySpec(it);
1813 /* Check if the to-be built/founded industry is available for this climate. */
1814 if (!indspec->enabled || indspec->num_table == 0) return CMD_ERROR;
1816 /* If the setting for raw-material industries is not on, you cannot build raw-material industries.
1817 * Raw material industries are industries that do not accept cargo (at least for now) */
1818 if (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 0 && indspec->IsRawIndustry()) {
1819 return CMD_ERROR;
1822 if (_game_mode != GM_EDITOR && GetIndustryProbabilityCallback(it, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, 1) == 0) {
1823 return CMD_ERROR;
1826 Randomizer randomizer;
1827 randomizer.SetSeed(p2);
1828 uint16 random_initial_bits = GB(p2, 0, 16);
1829 uint32 random_var8f = randomizer.Next();
1830 int num_layouts = indspec->num_table;
1831 CommandCost ret = CommandCost(STR_ERROR_SITE_UNSUITABLE);
1832 const bool deity_prospect = _current_company == OWNER_DEITY && !HasBit(p1, 16);
1834 Industry *ind = NULL;
1835 if (deity_prospect || (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 2 && indspec->IsRawIndustry())) {
1836 if (flags & DC_EXEC) {
1837 /* Prospected industries are build as OWNER_TOWN to not e.g. be build on owned land of the founder */
1838 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
1839 /* Prospecting has a chance to fail, however we cannot guarantee that something can
1840 * be built on the map, so the chance gets lower when the map is fuller, but there
1841 * is nothing we can really do about that. */
1842 if (deity_prospect || Random() <= indspec->prospecting_chance) {
1843 for (int i = 0; i < 5000; i++) {
1844 /* We should not have more than one Random() in a function call
1845 * because parameter evaluation order is not guaranteed in the c++ standard
1847 tile = RandomTile();
1848 /* Start with a random layout */
1849 int layout = RandomRange(num_layouts);
1850 /* Check now each layout, starting with the random one */
1851 for (int j = 0; j < num_layouts; j++) {
1852 layout = (layout + 1) % num_layouts;
1853 ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, cur_company.GetOriginalValue(), _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_PROSPECTCREATION, &ind);
1854 if (ret.Succeeded()) break;
1856 if (ret.Succeeded()) break;
1859 cur_company.Restore();
1861 } else {
1862 int layout = GB(p1, 8, 8);
1863 if (layout >= num_layouts) return CMD_ERROR;
1865 /* Check subsequently each layout, starting with the given layout in p1 */
1866 for (int i = 0; i < num_layouts; i++) {
1867 layout = (layout + 1) % num_layouts;
1868 ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, _current_company, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, &ind);
1869 if (ret.Succeeded()) break;
1872 /* If it still failed, there's no suitable layout to build here, return the error */
1873 if (ret.Failed()) return ret;
1876 if ((flags & DC_EXEC) && ind != NULL && _game_mode != GM_EDITOR) {
1877 AdvertiseIndustryOpening(ind);
1880 return CommandCost(EXPENSES_OTHER, indspec->GetConstructionCost());
1885 * Create a new industry of random layout.
1886 * @param tile The location to build the industry.
1887 * @param type The industry type to build.
1888 * @param creation_type The circumstances the industry is created under.
1889 * @return the created industry or NULL if it failed.
1891 static Industry *CreateNewIndustry(TileIndex tile, IndustryType type, IndustryAvailabilityCallType creation_type)
1893 const IndustrySpec *indspec = GetIndustrySpec(type);
1895 uint32 seed = Random();
1896 uint32 seed2 = Random();
1897 Industry *i = NULL;
1898 CommandCost ret = CreateNewIndustryHelper(tile, type, DC_EXEC, indspec, RandomRange(indspec->num_table), seed, GB(seed2, 0, 16), OWNER_NONE, creation_type, &i);
1899 assert(i != NULL || ret.Failed());
1900 return i;
1904 * Compute the appearance probability for an industry during map creation.
1905 * @param it Industry type to compute.
1906 * @param [out] force_at_least_one Returns whether at least one instance should be forced on map creation.
1907 * @return Relative probability for the industry to appear.
1909 static uint32 GetScaledIndustryGenerationProbability(IndustryType it, bool *force_at_least_one)
1911 const IndustrySpec *ind_spc = GetIndustrySpec(it);
1912 uint32 chance = ind_spc->appear_creation[_settings_game.game_creation.landscape] * 16; // * 16 to increase precision
1913 if (!ind_spc->enabled || ind_spc->num_table == 0 ||
1914 (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == ID_FUND_ONLY) ||
1915 (chance = GetIndustryProbabilityCallback(it, IACT_MAPGENERATION, chance)) == 0) {
1916 *force_at_least_one = false;
1917 return 0;
1918 } else {
1919 /* We want industries appearing at coast to appear less often on bigger maps, as length of coast increases slower than map area.
1920 * For simplicity we scale in both cases, though scaling the probabilities of all industries has no effect. */
1921 chance = (ind_spc->check_proc == CHECK_REFINERY || ind_spc->check_proc == CHECK_OIL_RIG) ? ScaleByMapPerimeter(chance) : ScaleByMapSize(chance);
1923 *force_at_least_one = (chance > 0) && !(ind_spc->behaviour & INDUSTRYBEH_NOBUILT_MAPCREATION) && (_game_mode != GM_EDITOR);
1924 return chance;
1929 * Compute the probability for constructing a new industry during game play.
1930 * @param it Industry type to compute.
1931 * @param [out] min_number Minimal number of industries that should exist at the map.
1932 * @return Relative probability for the industry to appear.
1934 static uint16 GetIndustryGamePlayProbability(IndustryType it, byte *min_number)
1936 if (_settings_game.difficulty.industry_density == ID_FUND_ONLY) {
1937 *min_number = 0;
1938 return 0;
1941 const IndustrySpec *ind_spc = GetIndustrySpec(it);
1942 byte chance = ind_spc->appear_ingame[_settings_game.game_creation.landscape];
1943 if (!ind_spc->enabled || ind_spc->num_table == 0 ||
1944 ((ind_spc->behaviour & INDUSTRYBEH_BEFORE_1950) && _cur_year > 1950) ||
1945 ((ind_spc->behaviour & INDUSTRYBEH_AFTER_1960) && _cur_year < 1960) ||
1946 (chance = GetIndustryProbabilityCallback(it, IACT_RANDOMCREATION, chance)) == 0) {
1947 *min_number = 0;
1948 return 0;
1950 *min_number = (ind_spc->behaviour & INDUSTRYBEH_CANCLOSE_LASTINSTANCE) ? 1 : 0;
1951 return chance;
1955 * Get wanted number of industries on the map.
1956 * @return Wanted number of industries at the map.
1958 static uint GetNumberOfIndustries()
1960 /* Number of industries on a 256x256 map. */
1961 static const uint16 numof_industry_table[] = {
1962 0, // none
1963 0, // minimal
1964 10, // very low
1965 25, // low
1966 55, // normal
1967 80, // high
1970 assert(lengthof(numof_industry_table) == ID_END);
1971 uint difficulty = (_game_mode != GM_EDITOR) ? _settings_game.difficulty.industry_density : (uint)ID_VERY_LOW;
1972 return min(Industry::Pool::MAX_SIZE, ScaleByMapSize(numof_industry_table[difficulty]));
1976 * Try to place the industry in the game.
1977 * Since there is no feedback why placement fails, there is no other option
1978 * than to try a few times before concluding it does not work.
1979 * @param type Industry type of the desired industry.
1980 * @param try_hard Try very hard to find a place. (Used to place at least one industry per type.)
1981 * @return Pointer to created industry, or \c NULL if creation failed.
1983 static Industry *PlaceIndustry(IndustryType type, IndustryAvailabilityCallType creation_type, bool try_hard)
1985 uint tries = try_hard ? 10000u : 2000u;
1986 for (; tries > 0; tries--) {
1987 Industry *ind = CreateNewIndustry(RandomTile(), type, creation_type);
1988 if (ind != NULL) return ind;
1990 return NULL;
1994 * Try to build a industry on the map.
1995 * @param type IndustryType of the desired industry
1996 * @param try_hard Try very hard to find a place. (Used to place at least one industry per type)
1998 static void PlaceInitialIndustry(IndustryType type, bool try_hard)
2000 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
2002 IncreaseGeneratingWorldProgress(GWP_INDUSTRY);
2003 PlaceIndustry(type, IACT_MAPGENERATION, try_hard);
2005 cur_company.Restore();
2009 * Get total number of industries existing in the game.
2010 * @return Number of industries currently in the game.
2012 static uint GetCurrentTotalNumberOfIndustries()
2014 int total = 0;
2015 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) total += Industry::GetIndustryTypeCount(it);
2016 return total;
2020 /** Reset the entry. */
2021 void IndustryTypeBuildData::Reset()
2023 this->probability = 0;
2024 this->min_number = 0;
2025 this->target_count = 0;
2026 this->max_wait = 1;
2027 this->wait_count = 0;
2030 /** Completely reset the industry build data. */
2031 void IndustryBuildData::Reset()
2033 this->wanted_inds = GetCurrentTotalNumberOfIndustries() << 16;
2035 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2036 this->builddata[it].Reset();
2040 /** Monthly update of industry build data. */
2041 void IndustryBuildData::MonthlyLoop()
2043 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.
2044 if (_settings_game.difficulty.industry_density == ID_FUND_ONLY) return; // 'no industries' setting.
2046 /* To prevent running out of unused industries for the player to connect,
2047 * add a fraction of new industries each month, but only if the manager can keep up. */
2048 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).
2049 if (GetCurrentTotalNumberOfIndustries() + max_behind >= (this->wanted_inds >> 16)) {
2050 this->wanted_inds += ScaleByMapSize(NEWINDS_PER_MONTH);
2055 * This function will create random industries during game creation.
2056 * It will scale the amount of industries by mapsize and difficulty level.
2058 void GenerateIndustries()
2060 if (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == ID_FUND_ONLY) return; // No industries in the game.
2062 uint32 industry_probs[NUM_INDUSTRYTYPES];
2063 bool force_at_least_one[NUM_INDUSTRYTYPES];
2064 uint32 total_prob = 0;
2065 uint num_forced = 0;
2067 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2068 industry_probs[it] = GetScaledIndustryGenerationProbability(it, force_at_least_one + it);
2069 total_prob += industry_probs[it];
2070 if (force_at_least_one[it]) num_forced++;
2073 uint total_amount = GetNumberOfIndustries();
2074 if (total_prob == 0 || total_amount < num_forced) {
2075 /* Only place the forced ones */
2076 total_amount = num_forced;
2079 SetGeneratingWorldProgress(GWP_INDUSTRY, total_amount);
2081 /* Try to build one industry per type independent of any probabilities */
2082 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2083 if (force_at_least_one[it]) {
2084 assert(total_amount > 0);
2085 total_amount--;
2086 PlaceInitialIndustry(it, true);
2090 /* Add the remaining industries according to their probabilities */
2091 for (uint i = 0; i < total_amount; i++) {
2092 uint32 r = RandomRange(total_prob);
2093 IndustryType it = 0;
2094 while (r >= industry_probs[it]) {
2095 r -= industry_probs[it];
2096 it++;
2097 assert(it < NUM_INDUSTRYTYPES);
2099 assert(industry_probs[it] > 0);
2100 PlaceInitialIndustry(it, false);
2102 _industry_builder.Reset();
2106 * Monthly update of industry statistics.
2107 * @param i Industry to update.
2109 static void UpdateIndustryStatistics(Industry *i)
2111 for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
2112 if (i->produced_cargo[j] != CT_INVALID) {
2113 byte pct = 0;
2114 if (i->this_month_production[j] != 0) {
2115 i->last_prod_year = _cur_year;
2116 pct = min(i->this_month_transported[j] * 256 / i->this_month_production[j], 255);
2118 i->last_month_pct_transported[j] = pct;
2120 i->last_month_production[j] = i->this_month_production[j];
2121 i->this_month_production[j] = 0;
2123 i->last_month_transported[j] = i->this_month_transported[j];
2124 i->this_month_transported[j] = 0;
2130 * Recompute #production_rate for current #prod_level.
2131 * This function is only valid when not using smooth economy.
2133 void Industry::RecomputeProductionMultipliers()
2135 const IndustrySpec *indspec = GetIndustrySpec(this->type);
2136 assert(!indspec->UsesSmoothEconomy());
2138 /* Rates are rounded up, so e.g. oilrig always produces some passengers */
2139 this->production_rate[0] = min(CeilDiv(indspec->production_rate[0] * this->prod_level, PRODLEVEL_DEFAULT), 0xFF);
2140 this->production_rate[1] = min(CeilDiv(indspec->production_rate[1] * this->prod_level, PRODLEVEL_DEFAULT), 0xFF);
2145 * Set the #probability and #min_number fields for the industry type \a it for a running game.
2146 * @param it Industry type.
2147 * @return At least one of the fields has changed value.
2149 bool IndustryTypeBuildData::GetIndustryTypeData(IndustryType it)
2151 byte min_number;
2152 uint32 probability = GetIndustryGamePlayProbability(it, &min_number);
2153 bool changed = min_number != this->min_number || probability != this->probability;
2154 this->min_number = min_number;
2155 this->probability = probability;
2156 return changed;
2159 /** Decide how many industries of each type are needed. */
2160 void IndustryBuildData::SetupTargetCount()
2162 bool changed = false;
2163 uint num_planned = 0; // Number of industries planned in the industry build data.
2164 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2165 changed |= this->builddata[it].GetIndustryTypeData(it);
2166 num_planned += this->builddata[it].target_count;
2168 uint total_amount = this->wanted_inds >> 16; // Desired total number of industries.
2169 changed |= num_planned != total_amount;
2170 if (!changed) return; // All industries are still the same, no need to re-randomize.
2172 /* Initialize the target counts. */
2173 uint force_build = 0; // Number of industries that should always be available.
2174 uint32 total_prob = 0; // Sum of probabilities.
2175 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2176 IndustryTypeBuildData *ibd = this->builddata + it;
2177 force_build += ibd->min_number;
2178 ibd->target_count = ibd->min_number;
2179 total_prob += ibd->probability;
2182 if (total_prob == 0) return; // No buildable industries.
2184 /* Subtract forced industries from the number of industries available for construction. */
2185 total_amount = (total_amount <= force_build) ? 0 : total_amount - force_build;
2187 /* Assign number of industries that should be aimed for, by using the probability as a weight. */
2188 while (total_amount > 0) {
2189 uint32 r = RandomRange(total_prob);
2190 IndustryType it = 0;
2191 while (r >= this->builddata[it].probability) {
2192 r -= this->builddata[it].probability;
2193 it++;
2194 assert(it < NUM_INDUSTRYTYPES);
2196 assert(this->builddata[it].probability > 0);
2197 this->builddata[it].target_count++;
2198 total_amount--;
2203 * Try to create a random industry, during gameplay
2205 void IndustryBuildData::TryBuildNewIndustry()
2207 this->SetupTargetCount();
2209 int missing = 0; // Number of industries that need to be build.
2210 uint count = 0; // Number of industry types eligible for build.
2211 uint32 total_prob = 0; // Sum of probabilities.
2212 IndustryType forced_build = NUM_INDUSTRYTYPES; // Industry type that should be forcibly build.
2213 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2214 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
2215 missing += difference;
2216 if (this->builddata[it].wait_count > 0) continue; // This type may not be built now.
2217 if (difference > 0) {
2218 if (Industry::GetIndustryTypeCount(it) == 0 && this->builddata[it].min_number > 0) {
2219 /* An industry that should exist at least once, is not available. Force it, trying the most needed one first. */
2220 if (forced_build == NUM_INDUSTRYTYPES ||
2221 difference > this->builddata[forced_build].target_count - Industry::GetIndustryTypeCount(forced_build)) {
2222 forced_build = it;
2225 total_prob += difference;
2226 count++;
2230 if (EconomyIsInRecession() || (forced_build == NUM_INDUSTRYTYPES && (missing <= 0 || total_prob == 0))) count = 0; // Skip creation of an industry.
2232 if (count >= 1) {
2233 /* If not forced, pick a weighted random industry to build.
2234 * For the case that count == 1, there is no need to draw a random number. */
2235 IndustryType it;
2236 if (forced_build != NUM_INDUSTRYTYPES) {
2237 it = forced_build;
2238 } else {
2239 /* Non-forced, select an industry type to build (weighted random). */
2240 uint32 r = 0; // Initialized to silence the compiler.
2241 if (count > 1) r = RandomRange(total_prob);
2242 for (it = 0; it < NUM_INDUSTRYTYPES; it++) {
2243 if (this->builddata[it].wait_count > 0) continue; // Type may not be built now.
2244 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
2245 if (difference <= 0) continue; // Too many of this kind.
2246 if (count == 1) break;
2247 if (r < (uint)difference) break;
2248 r -= difference;
2250 assert(it < NUM_INDUSTRYTYPES && this->builddata[it].target_count > Industry::GetIndustryTypeCount(it));
2253 /* Try to create the industry. */
2254 const Industry *ind = PlaceIndustry(it, IACT_RANDOMCREATION, false);
2255 if (ind == NULL) {
2256 this->builddata[it].wait_count = this->builddata[it].max_wait + 1; // Compensate for decrementing below.
2257 this->builddata[it].max_wait = min(1000, this->builddata[it].max_wait + 2);
2258 } else {
2259 AdvertiseIndustryOpening(ind);
2260 this->builddata[it].max_wait = max(this->builddata[it].max_wait / 2, 1); // Reduce waiting time of the industry type.
2264 /* Decrement wait counters. */
2265 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2266 if (this->builddata[it].wait_count > 0) this->builddata[it].wait_count--;
2271 * Protects an industry from closure if the appropriate flags and conditions are met
2272 * INDUSTRYBEH_CANCLOSE_LASTINSTANCE must be set (which, by default, it is not) and the
2273 * count of industries of this type must one (or lower) in order to be protected
2274 * against closure.
2275 * @param type IndustryType been queried
2276 * @result true if protection is on, false otherwise (except for oil wells)
2278 static bool CheckIndustryCloseDownProtection(IndustryType type)
2280 const IndustrySpec *indspec = GetIndustrySpec(type);
2282 /* oil wells (or the industries with that flag set) are always allowed to closedown */
2283 if ((indspec->behaviour & INDUSTRYBEH_DONT_INCR_PROD) && _settings_game.game_creation.landscape == LT_TEMPERATE) return false;
2284 return (indspec->behaviour & INDUSTRYBEH_CANCLOSE_LASTINSTANCE) == 0 && Industry::GetIndustryTypeCount(type) <= 1;
2288 * Can given cargo type be accepted or produced by the industry?
2289 * @param cargo: Cargo type
2290 * @param ind: Industry
2291 * @param *c_accepts: Pointer to boolean for acceptance of cargo
2292 * @param *c_produces: Pointer to boolean for production of cargo
2293 * @return: \c *c_accepts is set when industry accepts the cargo type,
2294 * \c *c_produces is set when the industry produces the cargo type
2296 static void CanCargoServiceIndustry(CargoID cargo, Industry *ind, bool *c_accepts, bool *c_produces)
2298 if (cargo == CT_INVALID) return;
2300 /* Check for acceptance of cargo */
2301 for (byte j = 0; j < lengthof(ind->accepts_cargo); j++) {
2302 if (cargo == ind->accepts_cargo[j] && !IndustryTemporarilyRefusesCargo(ind, cargo)) {
2303 *c_accepts = true;
2304 break;
2308 /* Check for produced cargo */
2309 for (byte j = 0; j < lengthof(ind->produced_cargo); j++) {
2310 if (cargo == ind->produced_cargo[j]) {
2311 *c_produces = true;
2312 break;
2318 * Compute who can service the industry.
2320 * Here, 'can service' means that he/she has trains and stations close enough
2321 * to the industry with the right cargo type and the right orders (ie has the
2322 * technical means).
2324 * @param ind: Industry being investigated.
2326 * @return The NewsType to use for a production change in this industry.
2328 static NewsType IndustryServiceNewsType (Industry *ind)
2330 /* Find all stations within reach of the industry */
2331 StationList stations;
2332 FindStationsAroundTiles(ind->location, &stations);
2334 if (stations.Length() == 0) return NT_INDUSTRY_NOBODY; // No stations found at all
2336 const Vehicle *v;
2337 int result = 0;
2338 FOR_ALL_VEHICLES(v) {
2339 /* Is it worthwhile to try this vehicle? */
2340 if (v->owner != _local_company && result != 0) continue;
2342 /* Check whether it accepts the right kind of cargo */
2343 bool c_accepts = false;
2344 bool c_produces = false;
2345 if (v->type == VEH_TRAIN && v->IsFrontEngine()) {
2346 for (const Vehicle *u = v; u != NULL; u = u->Next()) {
2347 CanCargoServiceIndustry(u->cargo_type, ind, &c_accepts, &c_produces);
2349 } else if (v->type == VEH_ROAD || v->type == VEH_SHIP || v->type == VEH_AIRCRAFT) {
2350 CanCargoServiceIndustry(v->cargo_type, ind, &c_accepts, &c_produces);
2351 } else {
2352 continue;
2354 if (!c_accepts && !c_produces) continue; // Wrong cargo
2356 /* Check orders of the vehicle.
2357 * We cannot check the first of shared orders only, since the first vehicle in such a chain
2358 * may have a different cargo type.
2360 const Order *o;
2361 FOR_VEHICLE_ORDERS(v, o) {
2362 if (o->IsType(OT_GOTO_STATION) && !(o->GetUnloadType() & OUFB_TRANSFER)) {
2363 /* Vehicle visits a station to load or unload */
2364 Station *st = Station::Get(o->GetDestination());
2365 assert(st != NULL);
2367 /* Same cargo produced by industry is dropped here => not serviced by vehicle v */
2368 if ((o->GetUnloadType() & OUFB_UNLOAD) && !c_accepts) break;
2370 if (stations.Contains(st)) {
2371 if (v->owner == _local_company) return NT_INDUSTRY_COMPANY; // Company services industry
2372 result = 1; // Competitor services industry
2377 return result ? NT_INDUSTRY_OTHER : NT_INDUSTRY_NOBODY;
2380 static const uint PERCENT_TRANSPORTED_60 = 153;
2381 static const uint PERCENT_TRANSPORTED_80 = 204;
2384 * Change industry production smoothly for standard industries.
2385 * @param i Industry for which changes are performed.
2386 * @param only_decrease Whether production can only decrease (temperate oil wells).
2387 * @param on_water Whether the industry is built on water (oil rigs).
2388 * @return Whether the industry should be closed.
2390 static bool ChangeIndustryProductionSmooth (Industry *i,
2391 bool only_decrease, bool on_water)
2393 bool close = true;
2395 for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
2396 if (i->produced_cargo[j] == CT_INVALID) continue;
2398 uint32 r = Random();
2400 assert_compile (PERCENT_TRANSPORTED_80 > PERCENT_TRANSPORTED_60);
2402 int mult;
2403 if (only_decrease) {
2404 /* For industries with only_decrease flags (temperate
2405 * terrain Oil Wells), the multiplier will always be
2406 * -1 so they will only decrease. */
2407 mult = -1;
2408 } else if (i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_80) {
2409 /* Bonus for very high station ratings:
2410 * 16% chance for decrease. */
2411 mult = Chance16I (1, 6, r) ? -1 : 1;
2412 } else {
2413 /* For normal industries, if over 60% is transported,
2414 * 33% chance for decrease, else 67% chance for decrease. */
2415 mult = ((i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_60) == Chance16I (1, 3, r)) ? -1 : 1;
2418 /* 4.5% chance for 3-23% (or 1 unit for very low productions) production change,
2419 * determined by mult value. If mult = 1 prod. increases, else (-1) it decreases. */
2420 int old_prod, new_prod;
2421 new_prod = old_prod = i->production_rate[j];
2422 if (Chance16I (1, 22, r >> 16)) {
2423 new_prod += mult * max (((RandomRange(50) + 10) * old_prod) >> 8, 1U);
2426 /* Prevent production to overflow or Oil Rig passengers to be over-"produced" */
2427 new_prod = Clamp (new_prod, 1, 255);
2429 if (on_water && j == 1) {
2430 new_prod = Clamp(new_prod, 0, 16);
2433 /* Do not stop closing the industry when it has the lowest possible production rate */
2434 if (new_prod == old_prod && old_prod > 1) {
2435 close = false;
2436 continue;
2439 int percent = (old_prod == 0) ? 100 : (new_prod * 100 / old_prod - 100);
2440 i->production_rate[j] = new_prod;
2442 /* Close the industry when it has the lowest possible production rate */
2443 if (new_prod > 1) close = false;
2445 int percent_abs = abs (percent);
2446 if (percent_abs >= 10) {
2447 AddNewsItem<IndustryNewsItem> (percent >= 0 ?
2448 STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH :
2449 STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH,
2450 IndustryServiceNewsType (i), i->index,
2451 CargoSpec::Get(i->produced_cargo[j])->name,
2452 i->index, percent_abs);
2456 return close;
2460 * Change industry production or do closure
2461 * @param i Industry for which changes are performed
2462 * @param monthly true if it's the monthly call, false if it's the random call
2464 static void ChangeIndustryProduction(Industry *i, bool monthly)
2466 StringID str = STR_NULL;
2467 bool closeit = false;
2468 const IndustrySpec *indspec = GetIndustrySpec(i->type);
2469 bool standard = false;
2470 bool suppress_message = false;
2471 bool recalculate_multipliers = false; ///< reinitialize production_rate to match prod_level
2472 /* don't use smooth economy for industries using production related callbacks */
2473 bool smooth_economy = indspec->UsesSmoothEconomy();
2474 byte div = 0;
2475 byte mul = 0;
2476 int8 increment = 0;
2478 bool callback_enabled = HasBit(indspec->callback_mask, monthly ? CBM_IND_MONTHLYPROD_CHANGE : CBM_IND_PRODUCTION_CHANGE);
2479 if (callback_enabled) {
2480 uint16 res = GetIndustryCallback(monthly ? CBID_INDUSTRY_MONTHLYPROD_CHANGE : CBID_INDUSTRY_PRODUCTION_CHANGE, 0, Random(), i, i->type, i->location.tile);
2481 if (res != CALLBACK_FAILED) { // failed callback means "do nothing"
2482 suppress_message = HasBit(res, 7);
2483 /* Get the custom message if any */
2484 if (HasBit(res, 8)) str = MapGRFStringID(indspec->grf_prop.grffile->grfid, GB(GetRegister(0x100), 0, 16));
2485 res = GB(res, 0, 4);
2486 switch (res) {
2487 default: NOT_REACHED();
2488 case 0x0: break; // Do nothing, but show the custom message if any
2489 case 0x1: div = 1; break; // Halve industry production. If production reaches the quarter of the default, the industry is closed instead.
2490 case 0x2: mul = 1; break; // Double industry production if it hasn't reached eight times of the original yet.
2491 case 0x3: closeit = true; break; // The industry announces imminent closure, and is physically removed from the map next month.
2492 case 0x4: standard = true; break; // Do the standard random production change as if this industry was a primary one.
2493 case 0x5: case 0x6: case 0x7: // Divide production by 4, 8, 16
2494 case 0x8: div = res - 0x3; break; // Divide production by 32
2495 case 0x9: case 0xA: case 0xB: // Multiply production by 4, 8, 16
2496 case 0xC: mul = res - 0x7; break; // Multiply production by 32
2497 case 0xD: // decrement production
2498 case 0xE: // increment production
2499 increment = res == 0x0D ? -1 : 1;
2500 break;
2501 case 0xF: // Set production to third byte of register 0x100
2502 i->prod_level = Clamp(GB(GetRegister(0x100), 16, 8), PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
2503 recalculate_multipliers = true;
2504 break;
2507 } else {
2508 if (monthly != smooth_economy) return;
2509 if (indspec->life_type == INDUSTRYLIFE_BLACK_HOLE) return;
2512 if (standard || (!callback_enabled && (indspec->life_type & (INDUSTRYLIFE_ORGANIC | INDUSTRYLIFE_EXTRACTIVE)) != 0)) {
2513 /* decrease or increase */
2514 bool only_decrease = (indspec->behaviour & INDUSTRYBEH_DONT_INCR_PROD) && _settings_game.game_creation.landscape == LT_TEMPERATE;
2516 if (smooth_economy) {
2517 closeit = ChangeIndustryProductionSmooth (i, only_decrease,
2518 (indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0);
2519 } else {
2520 if (only_decrease || Chance16(1, 3)) {
2521 /* If more than 60% transported, 66% chance of increase, else 33% chance of increase */
2522 if (!only_decrease && (i->last_month_pct_transported[0] > PERCENT_TRANSPORTED_60) != Chance16(1, 3)) {
2523 mul = 1; // Increase production
2524 } else {
2525 div = 1; // Decrease production
2531 if (!callback_enabled && (indspec->life_type & INDUSTRYLIFE_PROCESSING)) {
2532 if ( (byte)(_cur_year - i->last_prod_year) >= 5 && Chance16(1, smooth_economy ? 180 : 2)) {
2533 closeit = true;
2537 /* Increase if needed */
2538 while (mul-- != 0 && i->prod_level < PRODLEVEL_MAXIMUM) {
2539 i->prod_level = min(i->prod_level * 2, PRODLEVEL_MAXIMUM);
2540 recalculate_multipliers = true;
2541 if (str == STR_NULL) str = indspec->production_up_text;
2544 /* Decrease if needed */
2545 while (div-- != 0 && !closeit) {
2546 if (i->prod_level == PRODLEVEL_MINIMUM) {
2547 closeit = true;
2548 } else {
2549 i->prod_level = max(i->prod_level / 2, (int)PRODLEVEL_MINIMUM); // typecast to int required to please MSVC
2550 recalculate_multipliers = true;
2551 if (str == STR_NULL) str = indspec->production_down_text;
2555 /* Increase or Decreasing the production level if needed */
2556 if (increment != 0) {
2557 if (increment < 0 && i->prod_level == PRODLEVEL_MINIMUM) {
2558 closeit = true;
2559 } else {
2560 i->prod_level = ClampU(i->prod_level + increment, PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
2561 recalculate_multipliers = true;
2565 /* Recalculate production_rate
2566 * For non-smooth economy these should always be synchronized with prod_level */
2567 if (recalculate_multipliers) i->RecomputeProductionMultipliers();
2569 /* Close if needed and allowed */
2570 if (closeit && !CheckIndustryCloseDownProtection(i->type)) {
2571 i->prod_level = PRODLEVEL_CLOSURE;
2572 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
2573 str = indspec->closure_text;
2576 if (!suppress_message && str != STR_NULL) {
2577 NewsType nt;
2578 /* Compute news category */
2579 if (closeit) {
2580 nt = NT_INDUSTRY_CLOSE;
2581 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index));
2582 Game::NewEvent(new ScriptEventIndustryClose(i->index));
2583 } else {
2584 nt = IndustryServiceNewsType (i);
2586 /* Report the news to the user. */
2587 uint p0 = (str > STR_LAST_STRINGID) ? STR_TOWN_NAME :
2588 closeit ? STR_FORMAT_INDUSTRY_NAME : i->index;
2589 if (closeit) {
2590 AddNewsItem<TileNewsItem> (str, nt,
2591 i->location.tile + TileDiffXY(1, 1),
2592 p0, i->town->index, indspec->name);
2593 } else {
2594 AddNewsItem<IndustryNewsItem> (str, nt, i->index,
2595 p0, i->town->index, indspec->name);
2601 * Daily handler for the industry changes
2602 * Taking the original map size of 256*256, the number of random changes was always of just one unit.
2603 * But it cannot be the same on smaller or bigger maps. That number has to be scaled up or down.
2604 * For small maps, it implies that less than one change per month is required, while on bigger maps,
2605 * it would be way more. The daily loop handles those changes.
2607 void IndustryDailyLoop()
2609 _economy.industry_daily_change_counter += _economy.industry_daily_increment;
2611 /* Bits 16-31 of industry_construction_counter contain the number of industries to change/create today,
2612 * the lower 16 bit are a fractional part that might accumulate over several days until it
2613 * is sufficient for an industry. */
2614 uint16 change_loop = _economy.industry_daily_change_counter >> 16;
2616 /* Reset the active part of the counter, just keeping the "fractional part" */
2617 _economy.industry_daily_change_counter &= 0xFFFF;
2619 if (change_loop == 0) {
2620 return; // Nothing to do? get out
2623 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
2625 /* perform the required industry changes for the day */
2627 uint perc = 3; // Between 3% and 9% chance of creating a new industry.
2628 if ((_industry_builder.wanted_inds >> 16) > GetCurrentTotalNumberOfIndustries()) {
2629 perc = min(9u, perc + (_industry_builder.wanted_inds >> 16) - GetCurrentTotalNumberOfIndustries());
2631 for (uint16 j = 0; j < change_loop; j++) {
2632 if (Chance16(perc, 100)) {
2633 _industry_builder.TryBuildNewIndustry();
2634 } else {
2635 Industry *i = Industry::GetRandom();
2636 if (i != NULL) {
2637 ChangeIndustryProduction(i, false);
2638 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
2643 cur_company.Restore();
2645 /* production-change */
2646 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 1);
2649 void IndustryMonthlyLoop()
2651 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
2653 _industry_builder.MonthlyLoop();
2655 Industry *i;
2656 FOR_ALL_INDUSTRIES(i) {
2657 UpdateIndustryStatistics(i);
2658 if (i->prod_level == PRODLEVEL_CLOSURE) {
2659 delete i;
2660 } else {
2661 ChangeIndustryProduction(i, true);
2662 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
2666 cur_company.Restore();
2668 /* production-change */
2669 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 1);
2673 void InitializeIndustries()
2675 Industry::ResetIndustryCounts();
2676 _industry_sound_tile = 0;
2678 _industry_builder.Reset();
2681 /** Verify whether the generated industries are complete, and warn the user if not. */
2682 void CheckIndustries()
2684 int count = 0;
2685 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2686 if (Industry::GetIndustryTypeCount(it) > 0) continue; // Types of existing industries can be skipped.
2688 bool force_at_least_one;
2689 uint32 chance = GetScaledIndustryGenerationProbability(it, &force_at_least_one);
2690 if (chance == 0 || !force_at_least_one) continue; // Types that are not available can be skipped.
2692 const IndustrySpec *is = GetIndustrySpec(it);
2693 SetDParam(0, is->name);
2694 ShowErrorMessage(STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES, STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION, WL_WARNING);
2696 count++;
2697 if (count >= 3) break; // Don't swamp the user with errors.
2702 * Is an industry with the spec a raw industry?
2703 * @return true if it should be handled as a raw industry
2705 bool IndustrySpec::IsRawIndustry() const
2707 return (this->life_type & (INDUSTRYLIFE_EXTRACTIVE | INDUSTRYLIFE_ORGANIC)) != 0;
2711 * Is an industry with the spec a processing industry?
2712 * @return true if it should be handled as a processing industry
2714 bool IndustrySpec::IsProcessingIndustry() const
2716 /* Lumber mills are neither raw nor processing */
2717 return (this->life_type & INDUSTRYLIFE_PROCESSING) != 0 &&
2718 (this->behaviour & INDUSTRYBEH_CUT_TREES) == 0;
2722 * Get the cost for constructing this industry
2723 * @return the cost (inflation corrected etc)
2725 Money IndustrySpec::GetConstructionCost() const
2727 /* Building raw industries like secondary uses different price base */
2728 return (_price[(_settings_game.construction.raw_industry_construction == 1 && this->IsRawIndustry()) ?
2729 PR_BUILD_INDUSTRY_RAW : PR_BUILD_INDUSTRY] * this->cost_multiplier) >> 8;
2733 * Get the cost for removing this industry
2734 * Take note that the cost will always be zero for non-grf industries.
2735 * Only if the grf author did specified a cost will it be applicable.
2736 * @return the cost (inflation corrected etc)
2738 Money IndustrySpec::GetRemovalCost() const
2740 return (_price[PR_CLEAR_INDUSTRY] * this->removal_cost_multiplier) >> 8;
2744 * Determines whether this industrytype uses smooth economy or whether it uses standard/newgrf production changes.
2745 * @return true if smooth economy is used.
2747 bool IndustrySpec::UsesSmoothEconomy() const
2749 return _settings_game.economy.smooth_economy &&
2750 !(HasBit(this->callback_mask, CBM_IND_PRODUCTION_256_TICKS) || HasBit(this->callback_mask, CBM_IND_PRODUCTION_CARGO_ARRIVAL)) && // production callbacks
2751 !(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
2754 static CommandCost TerraformTile_Industry(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
2756 if (AutoslopeEnabled()) {
2757 /* We imitate here TTDP's behaviour:
2758 * - Both new and old slope must not be steep.
2759 * - TileMaxZ must not be changed.
2760 * - Allow autoslope by default.
2761 * - Disallow autoslope if callback succeeds and returns non-zero.
2763 Slope tileh_old = GetTileSlope(tile);
2764 /* TileMaxZ must not be changed. Slopes must not be steep. */
2765 if (!IsSteepSlope(tileh_old) && !IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) {
2766 const IndustryGfx gfx = GetIndustryGfx(tile);
2767 const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
2769 /* Call callback 3C 'disable autosloping for industry tiles'. */
2770 if (HasBit(itspec->callback_mask, CBM_INDT_AUTOSLOPE)) {
2771 /* If the callback fails, allow autoslope. */
2772 uint16 res = GetIndustryTileCallback(CBID_INDTILE_AUTOSLOPE, 0, 0, gfx, Industry::GetByTile(tile), tile);
2773 if (res == CALLBACK_FAILED || !ConvertBooleanCallback(itspec->grf_prop.grffile, CBID_INDTILE_AUTOSLOPE, res)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
2774 } else {
2775 /* allow autoslope */
2776 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
2780 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
2783 extern const TileTypeProcs _tile_type_industry_procs = {
2784 DrawTile_Industry, // draw_tile_proc
2785 GetSlopePixelZ_Industry, // get_slope_z_proc
2786 ClearTile_Industry, // clear_tile_proc
2787 AddAcceptedCargo_Industry, // add_accepted_cargo_proc
2788 GetTileDesc_Industry, // get_tile_desc_proc
2789 NULL, // get_tile_railway_status_proc
2790 NULL, // get_tile_road_status_proc
2791 NULL, // get_tile_waterway_status_proc
2792 ClickTile_Industry, // click_tile_proc
2793 AnimateTile_Industry, // animate_tile_proc
2794 TileLoop_Industry, // tile_loop_proc
2795 ChangeTileOwner_Industry, // change_tile_owner_proc
2796 NULL, // add_produced_cargo_proc
2797 GetFoundation_Industry, // get_foundation_proc
2798 TerraformTile_Industry, // terraform_tile_proc