OpenTTD: src/industry_cmd.cpp Source File

OpenTTD

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

industry_cmd.cpp
Go to the documentation of this file.
1 /* $Id: industry_cmd.cpp 27841 2017-04-02 17:36:53Z peter1138 $ */
2
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 */
9
12 #include "stdafx.h"
13 #include "clear_map.h"
14 #include "industry.h"
15 #include "station_base.h"
16 #include "landscape.h"
17 #include "viewport_func.h"
18 #include "command_func.h"
19 #include "town.h"
20 #include "news_func.h"
21 #include "cheat_type.h"
22 #include "genworld.h"
23 #include "tree_map.h"
24 #include "newgrf_cargo.h"
25 #include "newgrf_debug.h"
26 #include "newgrf_industrytiles.h"
27 #include "autoslope.h"
28 #include "water.h"
29 #include "strings_func.h"
30 #include "window_func.h"
31 #include "date_func.h"
32 #include "vehicle_func.h"
33 #include "sound_func.h"
34 #include "animated_tile_func.h"
35 #include "effectvehicle_func.h"
36 #include "effectvehicle_base.h"
37 #include "ai/ai.hpp"
38 #include "core/pool_func.hpp"
39 #include "subsidy_func.h"
40 #include "core/backup_type.hpp"
41 #include "object_base.h"
42 #include "game/game.hpp"
43 #include "error.h"
44
45 #include "table/strings.h"
46 #include "table/industry_land.h"
47 #include "table/build_industry.h"
48
49 #include "safeguards.h"
50
51 IndustryPool _industry_pool("Industry");
52 INSTANTIATE_POOL_METHODS(Industry)
53
54 void ShowIndustryViewWindow(int industry);
55 void BuildOilRig(TileIndex tile);
56
57 static byte _industry_sound_ctr;
58 static TileIndex _industry_sound_tile;
59
60 uint16 Industry::counts[NUM_INDUSTRYTYPES];
61
62 IndustrySpec _industry_specs[NUM_INDUSTRYTYPES];
63 IndustryTileSpec _industry_tile_specs[NUM_INDUSTRYTILES];
64 IndustryBuildData _industry_builder;
65
72 void ResetIndustries()
73 {
74 memset(&_industry_specs, 0, sizeof(_industry_specs));
75 memcpy(&_industry_specs, &_origin_industry_specs, sizeof(_origin_industry_specs));
76
77 /* once performed, enable only the current climate industries */
78 for (IndustryType i = 0; i < NUM_INDUSTRYTYPES; i++) {
79 _industry_specs[i].enabled = i < NEW_INDUSTRYOFFSET &&
80 HasBit(_origin_industry_specs[i].climate_availability, _settings_game.game_creation.landscape);
81 }
82
83 memset(&_industry_tile_specs, 0, sizeof(_industry_tile_specs));
84 memcpy(&_industry_tile_specs, &_origin_industry_tile_specs, sizeof(_origin_industry_tile_specs));
85
86 /* Reset any overrides that have been set. */
87 _industile_mngr.ResetOverride();
88 _industry_mngr.ResetOverride();
89 }
90
99 IndustryType GetIndustryType(TileIndex tile)
100 {
101 assert(IsTileType(tile, MP_INDUSTRY));
102
103 const Industry *ind = Industry::GetByTile(tile);
104 assert(ind != NULL);
105 return ind->type;
106 }
107
116 const IndustrySpec *GetIndustrySpec(IndustryType thistype)
117 {
118 assert(thistype < NUM_INDUSTRYTYPES);
119 return &_industry_specs[thistype];
120 }
121
130 const IndustryTileSpec *GetIndustryTileSpec(IndustryGfx gfx)
131 {
132 assert(gfx < INVALID_INDUSTRYTILE);
133 return &_industry_tile_specs[gfx];
134 }
135
136 Industry::~Industry()
137 {
138 if (CleaningPool()) return;
139
140 /* Industry can also be destroyed when not fully initialized.
141 * This means that we do not have to clear tiles either.
142 * Also we must not decrement industry counts in that case. */
143 if (this->location.w == 0) return;
144
145 TILE_AREA_LOOP(tile_cur, this->location) {
146 if (IsTileType(tile_cur, MP_INDUSTRY)) {
147 if (GetIndustryIndex(tile_cur) == this->index) {
148 DeleteNewGRFInspectWindow(GSF_INDUSTRYTILES, tile_cur);
149
150 /* MakeWaterKeepingClass() can also handle 'land' */
151 MakeWaterKeepingClass(tile_cur, OWNER_NONE);
152 }
153 } else if (IsTileType(tile_cur, MP_STATION) && IsOilRig(tile_cur)) {
154 DeleteOilRig(tile_cur);
155 }
156 }
157
158 if (GetIndustrySpec(this->type)->behaviour & INDUSTRYBEH_PLANT_FIELDS) {
159 TileArea ta(this->location.tile - TileDiffXY(min(TileX(this->location.tile), 21), min(TileY(this->location.tile), 21)), 42, 42);
160 ta.ClampToMap();
161
162 /* Remove the farmland and convert it to regular tiles over time. */
163 TILE_AREA_LOOP(tile_cur, ta) {
164 if (IsTileType(tile_cur, MP_CLEAR) && IsClearGround(tile_cur, CLEAR_FIELDS) &&
165 GetIndustryIndexOfField(tile_cur) == this->index) {
166 SetIndustryIndexOfField(tile_cur, INVALID_INDUSTRY);
167 }
168 }
169 }
170
171 /* don't let any disaster vehicle target invalid industry */
172 ReleaseDisastersTargetingIndustry(this->index);
173
174 /* Clear the persistent storage. */
175 delete this->psa;
176
177 DecIndustryTypeCount(this->type);
178
179 DeleteIndustryNews(this->index);
180 DeleteWindowById(WC_INDUSTRY_VIEW, this->index);
181 DeleteNewGRFInspectWindow(GSF_INDUSTRIES, this->index);
182
183 DeleteSubsidyWith(ST_INDUSTRY, this->index);
184 CargoPacket::InvalidateAllFrom(ST_INDUSTRY, this->index);
185 }
186
191 void Industry::PostDestructor(size_t index)
192 {
193 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0);
194 Station::RecomputeIndustriesNearForAll();
195 }
196
197
202 /* static */ Industry *Industry::GetRandom()
203 {
204 if (Industry::GetNumItems() == 0) return NULL;
205 int num = RandomRange((uint16)Industry::GetNumItems());
206 size_t index = MAX_UVALUE(size_t);
207
208 while (num >= 0) {
209 num--;
210 index++;
211
212 /* Make sure we have a valid industry */
213 while (!Industry::IsValidID(index)) {
214 index++;
215 assert(index < Industry::GetPoolSize());
216 }
217 }
218
219 return Industry::Get(index);
220 }
221
222
223 static void IndustryDrawSugarMine(const TileInfo *ti)
224 {
225 if (!IsIndustryCompleted(ti->tile)) return;
226
227 const DrawIndustryAnimationStruct *d = &_draw_industry_spec1[GetAnimationFrame(ti->tile)];
228
229 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_SIEVE + d->image_1, PAL_NONE, d->x, 0);
230
231 if (d->image_2 != 0) {
232 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_CLOUDS + d->image_2 - 1, PAL_NONE, 8, 41);
233 }
234
235 if (d->image_3 != 0) {
236 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_PILE + d->image_3 - 1, PAL_NONE,
237 _drawtile_proc1[d->image_3 - 1].x, _drawtile_proc1[d->image_3 - 1].y);
238 }
239 }
240
241 static void IndustryDrawToffeeQuarry(const TileInfo *ti)
242 {
243 uint8 x = 0;
244
245 if (IsIndustryCompleted(ti->tile)) {
246 x = _industry_anim_offs_toffee[GetAnimationFrame(ti->tile)];
247 if (x == 0xFF) {
248 x = 0;
249 }
250 }
251
252 AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_SHOVEL, PAL_NONE, 22 - x, 24 + x);
253 AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_TOFFEE, PAL_NONE, 6, 14);
254 }
255
256 static void IndustryDrawBubbleGenerator( const TileInfo *ti)
257 {
258 if (IsIndustryCompleted(ti->tile)) {
259 AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_BUBBLE, PAL_NONE, 5, _industry_anim_offs_bubbles[GetAnimationFrame(ti->tile)]);
260 }
261 AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_SPRING, PAL_NONE, 3, 67);
262 }
263
264 static void IndustryDrawToyFactory(const TileInfo *ti)
265 {
266 const DrawIndustryAnimationStruct *d = &_industry_anim_offs_toys[GetAnimationFrame(ti->tile)];
267
268 if (d->image_1 != 0xFF) {
269 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_CLAY, PAL_NONE, d->x, 96 + d->image_1);
270 }
271
272 if (d->image_2 != 0xFF) {
273 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_ROBOT, PAL_NONE, 16 - d->image_2 * 2, 100 + d->image_2);
274 }
275
276 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP, PAL_NONE, 7, d->image_3);
277 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP_HOLDER, PAL_NONE, 0, 42);
278 }
279
280 static void IndustryDrawCoalPlantSparks(const TileInfo *ti)
281 {
282 if (IsIndustryCompleted(ti->tile)) {
283 uint8 image = GetAnimationFrame(ti->tile);
284
285 if (image != 0 && image < 7) {
286 AddChildSpriteScreen(image + SPR_IT_POWER_PLANT_TRANSFORMERS,
287 PAL_NONE,
288 _coal_plant_sparks[image - 1].x,
289 _coal_plant_sparks[image - 1].y
290 );
291 }
292 }
293 }
294
295 typedef void IndustryDrawTileProc(const TileInfo *ti);
296 static IndustryDrawTileProc * const _industry_draw_tile_procs[5] = {
297 IndustryDrawSugarMine,
298 IndustryDrawToffeeQuarry,
299 IndustryDrawBubbleGenerator,
300 IndustryDrawToyFactory,
301 IndustryDrawCoalPlantSparks,
302 };
303
304 static void DrawTile_Industry(TileInfo *ti)
305 {
306 IndustryGfx gfx = GetIndustryGfx(ti->tile);
307 Industry *ind = Industry::GetByTile(ti->tile);
308 const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
309
310 /* Retrieve pointer to the draw industry tile struct */
311 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
312 /* Draw the tile using the specialized method of newgrf industrytile.
313 * DrawNewIndustry will return false if ever the resolver could not
314 * find any sprite to display. So in this case, we will jump on the
315 * substitute gfx instead. */
316 if (indts->grf_prop.spritegroup[0] != NULL && DrawNewIndustryTile(ti, ind, gfx, indts)) {
317 return;
318 } else {
319 /* No sprite group (or no valid one) found, meaning no graphics associated.
320 * Use the substitute one instead */
321 if (indts->grf_prop.subst_id != INVALID_INDUSTRYTILE) {
322 gfx = indts->grf_prop.subst_id;
323 /* And point the industrytile spec accordingly */
324 indts = GetIndustryTileSpec(gfx);
325 }
326 }
327 }
328
329 const DrawBuildingsTileStruct *dits = &_industry_draw_tile_data[gfx << 2 | (indts->anim_state ?
330 GetAnimationFrame(ti->tile) & INDUSTRY_COMPLETED :
331 GetIndustryConstructionStage(ti->tile))];
332
333 SpriteID image = dits->ground.sprite;
334
335 /* DrawFoundation() modifies ti->z and ti->tileh */
336 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
337
338 /* If the ground sprite is the default flat water sprite, draw also canal/river borders.
339 * Do not do this if the tile's WaterClass is 'land'. */
340 if (image == SPR_FLAT_WATER_TILE && IsTileOnWater(ti->tile)) {
341 DrawWaterClassGround(ti);
342 } else {
343 DrawGroundSprite(image, GroundSpritePaletteTransform(image, dits->ground.pal, GENERAL_SPRITE_COLOUR(ind->random_colour)));
344 }
345
346 /* If industries are transparent and invisible, do not draw the upper part */
347 if (IsInvisibilitySet(TO_INDUSTRIES)) return;
348
349 /* Add industry on top of the ground? */
350 image = dits->building.sprite;
351 if (image != 0) {
352 AddSortableSpriteToDraw(image, SpriteLayoutPaletteTransform(image, dits->building.pal, GENERAL_SPRITE_COLOUR(ind->random_colour)),
353 ti->x + dits->subtile_x,
354 ti->y + dits->subtile_y,
355 dits->width,
356 dits->height,
357 dits->dz,
358 ti->z,
359 IsTransparencySet(TO_INDUSTRIES));
360
361 if (IsTransparencySet(TO_INDUSTRIES)) return;
362 }
363
364 {
365 int proc = dits->draw_proc - 1;
366 if (proc >= 0) _industry_draw_tile_procs[proc](ti);
367 }
368 }
369
370 static int GetSlopePixelZ_Industry(TileIndex tile, uint x, uint y)
371 {
372 return GetTileMaxPixelZ(tile);
373 }
374
375 static Foundation GetFoundation_Industry(TileIndex tile, Slope tileh)
376 {
377 IndustryGfx gfx = GetIndustryGfx(tile);
378
379 /* For NewGRF industry tiles we might not be drawing a foundation. We need to
380 * account for this, as other structures should
381 * draw the wall of the foundation in this case.
382 */
383 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
384 const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
385 if (indts->grf_prop.spritegroup[0] != NULL && HasBit(indts->callback_mask, CBM_INDT_DRAW_FOUNDATIONS)) {
386 uint32 callback_res = GetIndustryTileCallback(CBID_INDTILE_DRAW_FOUNDATIONS, 0, 0, gfx, Industry::GetByTile(tile), tile);
387 if (callback_res != CALLBACK_FAILED && !ConvertBooleanCallback(indts->grf_prop.grffile, CBID_INDTILE_DRAW_FOUNDATIONS, callback_res)) return FOUNDATION_NONE;
388 }
389 }
390 return FlatteningFoundation(tileh);
391 }
392
393 static void AddAcceptedCargo_Industry(TileIndex tile, CargoArray &acceptance, uint32 *always_accepted)
394 {
395 IndustryGfx gfx = GetIndustryGfx(tile);
396 const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
397
398 /* When we have to use a callback, we put our data in the next two variables */
399 CargoID raw_accepts_cargo[lengthof(itspec->accepts_cargo)];
400 uint8 raw_cargo_acceptance[lengthof(itspec->acceptance)];
401
402 /* And then these will always point to a same sized array with the required data */
403 const CargoID *accepts_cargo = itspec->accepts_cargo;
404 const uint8 *cargo_acceptance = itspec->acceptance;
405
406 if (HasBit(itspec->callback_mask, CBM_INDT_ACCEPT_CARGO)) {
407 uint16 res = GetIndustryTileCallback(CBID_INDTILE_ACCEPT_CARGO, 0, 0, gfx, Industry::GetByTile(tile), tile);
408 if (res != CALLBACK_FAILED) {
409 accepts_cargo = raw_accepts_cargo;
410 for (uint i = 0; i < lengthof(itspec->accepts_cargo); i++) raw_accepts_cargo[i] = GetCargoTranslation(GB(res, i * 5, 5), itspec->grf_prop.grffile);
411 }
412 }
413
414 if (HasBit(itspec->callback_mask, CBM_INDT_CARGO_ACCEPTANCE)) {
415 uint16 res = GetIndustryTileCallback(CBID_INDTILE_CARGO_ACCEPTANCE, 0, 0, gfx, Industry::GetByTile(tile), tile);
416 if (res != CALLBACK_FAILED) {
417 cargo_acceptance = raw_cargo_acceptance;
418 for (uint i = 0; i < lengthof(itspec->accepts_cargo); i++) raw_cargo_acceptance[i] = GB(res, i * 4, 4);
419 }
420 }
421
422 const Industry *ind = Industry::GetByTile(tile);
423 for (byte i = 0; i < lengthof(itspec->accepts_cargo); i++) {
424 CargoID a = accepts_cargo[i];
425 if (a == CT_INVALID || cargo_acceptance[i] == 0) continue; // work only with valid cargoes
426
427 /* Add accepted cargo */
428 acceptance[a] += cargo_acceptance[i];
429
430 /* Maybe set 'always accepted' bit (if it's not set already) */
431 if (HasBit(*always_accepted, a)) continue;
432
433 bool accepts = false;
434 for (uint cargo_index = 0; cargo_index < lengthof(ind->accepts_cargo); cargo_index++) {
435 /* Test whether the industry itself accepts the cargo type */
436 if (ind->accepts_cargo[cargo_index] == a) {
437 accepts = true;
438 break;
439 }
440 }
441
442 if (accepts) continue;
443
444 /* If the industry itself doesn't accept this cargo, set 'always accepted' bit */
445 SetBit(*always_accepted, a);
446 }
447 }
448
449 static void GetTileDesc_Industry(TileIndex tile, TileDesc *td)
450 {
451 const Industry *i = Industry::GetByTile(tile);
452 const IndustrySpec *is = GetIndustrySpec(i->type);
453
454 td->owner[0] = i->owner;
455 td->str = is->name;
456 if (!IsIndustryCompleted(tile)) {
457 SetDParamX(td->dparam, 0, td->str);
458 td->str = STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION;
459 }
460
461 if (is->grf_prop.grffile != NULL) {
462 td->grf = GetGRFConfig(is->grf_prop.grffile->grfid)->GetName();
463 }
464 }
465
466 static CommandCost ClearTile_Industry(TileIndex tile, DoCommandFlag flags)
467 {
468 Industry *i = Industry::GetByTile(tile);
469 const IndustrySpec *indspec = GetIndustrySpec(i->type);
470
471 /* water can destroy industries
472 * in editor you can bulldoze industries
473 * with magic_bulldozer cheat you can destroy industries
474 * (area around OILRIG is water, so water shouldn't flood it
475 */
476 if ((_current_company != OWNER_WATER && _game_mode != GM_EDITOR &&
477 !_cheats.magic_bulldozer.value) ||
478 ((flags & DC_AUTO) != 0) ||
479 (_current_company == OWNER_WATER &&
480 ((indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) ||
481 HasBit(GetIndustryTileSpec(GetIndustryGfx(tile))->slopes_refused, 5)))) {
482 SetDParam(1, indspec->name);
483 return_cmd_error(flags & DC_AUTO ? STR_ERROR_GENERIC_OBJECT_IN_THE_WAY : INVALID_STRING_ID);
484 }
485
486 if (flags & DC_EXEC) {
487 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index));
488 Game::NewEvent(new ScriptEventIndustryClose(i->index));
489 delete i;
490 }
491 return CommandCost(EXPENSES_CONSTRUCTION, indspec->GetRemovalCost());
492 }
493
494 static void TransportIndustryGoods(TileIndex tile)
495 {
496 Industry *i = Industry::GetByTile(tile);
497 const IndustrySpec *indspec = GetIndustrySpec(i->type);
498 bool moved_cargo = false;
499
500 StationFinder stations(i->location);
501
502 for (uint j = 0; j < lengthof(i->produced_cargo_waiting); j++) {
503 uint cw = min(i->produced_cargo_waiting[j], 255);
504 if (cw > indspec->minimal_cargo && i->produced_cargo[j] != CT_INVALID) {
505 i->produced_cargo_waiting[j] -= cw;
506
507 /* fluctuating economy? */
508 if (EconomyIsInRecession()) cw = (cw + 1) / 2;
509
510 i->this_month_production[j] += cw;
511
512 uint am = MoveGoodsToStation(i->produced_cargo[j], cw, ST_INDUSTRY, i->index, stations.GetStations());
513 i->this_month_transported[j] += am;
514
515 moved_cargo |= (am != 0);
516 }
517 }
518
519 if (moved_cargo && !StartStopIndustryTileAnimation(i, IAT_INDUSTRY_DISTRIBUTES_CARGO)) {
520 uint newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_production;
521
522 if (newgfx != INDUSTRYTILE_NOANIM) {
523 ResetIndustryConstructionStage(tile);
524 SetIndustryCompleted(tile);
525 SetIndustryGfx(tile, newgfx);
526 MarkTileDirtyByTile(tile);
527 }
528 }
529 }
530
531
532 static void AnimateTile_Industry(TileIndex tile)
533 {
534 IndustryGfx gfx = GetIndustryGfx(tile);
535
536 if (GetIndustryTileSpec(gfx)->animation.status != ANIM_STATUS_NO_ANIMATION) {
537 AnimateNewIndustryTile(tile);
538 return;
539 }
540
541 switch (gfx) {
542 case GFX_SUGAR_MINE_SIEVE:
543 if ((_tick_counter & 1) == 0) {
544 byte m = GetAnimationFrame(tile) + 1;
545
546 if (_settings_client.sound.ambient) {
547 switch (m & 7) {
548 case 2: SndPlayTileFx(SND_2D_RIP_2, tile); break;
549 case 6: SndPlayTileFx(SND_29_RIP, tile); break;
550 }
551 }
552
553 if (m >= 96) {
554 m = 0;
555 DeleteAnimatedTile(tile);
556 }
557 SetAnimationFrame(tile, m);
558
559 MarkTileDirtyByTile(tile);
560 }
561 break;
562
563 case GFX_TOFFEE_QUARY:
564 if ((_tick_counter & 3) == 0) {
565 byte m = GetAnimationFrame(tile);
566
567 if (_industry_anim_offs_toffee[m] == 0xFF && _settings_client.sound.ambient) {
568 SndPlayTileFx(SND_30_CARTOON_SOUND, tile);
569 }
570
571 if (++m >= 70) {
572 m = 0;
573 DeleteAnimatedTile(tile);
574 }
575 SetAnimationFrame(tile, m);
576
577 MarkTileDirtyByTile(tile);
578 }
579 break;
580
581 case GFX_BUBBLE_CATCHER:
582 if ((_tick_counter & 1) == 0) {
583 byte m = GetAnimationFrame(tile);
584
585 if (++m >= 40) {
586 m = 0;
587 DeleteAnimatedTile(tile);
588 }
589 SetAnimationFrame(tile, m);
590
591 MarkTileDirtyByTile(tile);
592 }
593 break;
594
595 /* Sparks on a coal plant */
596 case GFX_POWERPLANT_SPARKS:
597 if ((_tick_counter & 3) == 0) {
598 byte m = GetAnimationFrame(tile);
599 if (m == 6) {
600 SetAnimationFrame(tile, 0);
601 DeleteAnimatedTile(tile);
602 } else {
603 SetAnimationFrame(tile, m + 1);
604 MarkTileDirtyByTile(tile);
605 }
606 }
607 break;
608
609 case GFX_TOY_FACTORY:
610 if ((_tick_counter & 1) == 0) {
611 byte m = GetAnimationFrame(tile) + 1;
612
613 switch (m) {
614 case 1: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2C_MACHINERY, tile); break;
615 case 23: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2B_COMEDY_HIT, tile); break;
616 case 28: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2A_EXTRACT_AND_POP, tile); break;
617 default:
618 if (m >= 50) {
619 int n = GetIndustryAnimationLoop(tile) + 1;
620 m = 0;
621 if (n >= 8) {
622 n = 0;
623 DeleteAnimatedTile(tile);
624 }
625 SetIndustryAnimationLoop(tile, n);
626 }
627 }
628
629 SetAnimationFrame(tile, m);
630 MarkTileDirtyByTile(tile);
631 }
632 break;
633
634 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
635 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
636 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
637 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
638 if ((_tick_counter & 3) == 0) {
639 IndustryGfx gfx = GetIndustryGfx(tile);
640
641 gfx = (gfx < 155) ? gfx + 1 : 148;
642 SetIndustryGfx(tile, gfx);
643 MarkTileDirtyByTile(tile);
644 }
645 break;
646
647 case GFX_OILWELL_ANIMATED_1:
648 case GFX_OILWELL_ANIMATED_2:
649 case GFX_OILWELL_ANIMATED_3:
650 if ((_tick_counter & 7) == 0) {
651 bool b = Chance16(1, 7);
652 IndustryGfx gfx = GetIndustryGfx(tile);
653
654 byte m = GetAnimationFrame(tile) + 1;
655 if (m == 4 && (m = 0, ++gfx) == GFX_OILWELL_ANIMATED_3 + 1 && (gfx = GFX_OILWELL_ANIMATED_1, b)) {
656 SetIndustryGfx(tile, GFX_OILWELL_NOT_ANIMATED);
657 SetIndustryConstructionStage(tile, 3);
658 DeleteAnimatedTile(tile);
659 } else {
660 SetAnimationFrame(tile, m);
661 SetIndustryGfx(tile, gfx);
662 MarkTileDirtyByTile(tile);
663 }
664 }
665 break;
666
667 case GFX_COAL_MINE_TOWER_ANIMATED:
668 case GFX_COPPER_MINE_TOWER_ANIMATED:
669 case GFX_GOLD_MINE_TOWER_ANIMATED: {
670 int state = _tick_counter & 0x7FF;
671
672 if ((state -= 0x400) < 0) return;
673
674 if (state < 0x1A0) {
675 if (state < 0x20 || state >= 0x180) {
676 byte m = GetAnimationFrame(tile);
677 if (!(m & 0x40)) {
678 SetAnimationFrame(tile, m | 0x40);
679 if (_settings_client.sound.ambient) SndPlayTileFx(SND_0B_MINING_MACHINERY, tile);
680 }
681 if (state & 7) return;
682 } else {
683 if (state & 3) return;
684 }
685 byte m = (GetAnimationFrame(tile) + 1) | 0x40;
686 if (m > 0xC2) m = 0xC0;
687 SetAnimationFrame(tile, m);
688 MarkTileDirtyByTile(tile);
689 } else if (state >= 0x200 && state < 0x3A0) {
690 int i = (state < 0x220 || state >= 0x380) ? 7 : 3;
691 if (state & i) return;
692
693 byte m = (GetAnimationFrame(tile) & 0xBF) - 1;
694 if (m < 0x80) m = 0x82;
695 SetAnimationFrame(tile, m);
696 MarkTileDirtyByTile(tile);
697 }
698 break;
699 }
700 }
701 }
702
703 static void CreateChimneySmoke(TileIndex tile)
704 {
705 uint x = TileX(tile) * TILE_SIZE;
706 uint y = TileY(tile) * TILE_SIZE;
707 int z = GetTileMaxPixelZ(tile);
708
709 CreateEffectVehicle(x + 15, y + 14, z + 59, EV_CHIMNEY_SMOKE);
710 }
711
712 static void MakeIndustryTileBigger(TileIndex tile)
713 {
714 byte cnt = GetIndustryConstructionCounter(tile) + 1;
715 if (cnt != 4) {
716 SetIndustryConstructionCounter(tile, cnt);
717 return;
718 }
719
720 byte stage = GetIndustryConstructionStage(tile) + 1;
721 SetIndustryConstructionCounter(tile, 0);
722 SetIndustryConstructionStage(tile, stage);
723 StartStopIndustryTileAnimation(tile, IAT_CONSTRUCTION_STATE_CHANGE);
724 if (stage == INDUSTRY_COMPLETED) SetIndustryCompleted(tile);
725
726 MarkTileDirtyByTile(tile);
727
728 if (!IsIndustryCompleted(tile)) return;
729
730 IndustryGfx gfx = GetIndustryGfx(tile);
731 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
732 /* New industries are already animated on construction. */
733 return;
734 }
735
736 switch (gfx) {
737 case GFX_POWERPLANT_CHIMNEY:
738 CreateChimneySmoke(tile);
739 break;
740
741 case GFX_OILRIG_1: {
742 /* Do not require an industry tile to be after the first two GFX_OILRIG_1
743 * tiles (like the default oil rig). Do a proper check to ensure the
744 * tiles belong to the same industry and based on that build the oil rig's
745 * station. */
746 TileIndex other = tile + TileDiffXY(0, 1);
747
748 if (IsTileType(other, MP_INDUSTRY) &&
749 GetIndustryGfx(other) == GFX_OILRIG_1 &&
750 GetIndustryIndex(tile) == GetIndustryIndex(other)) {
751 BuildOilRig(tile);
752 }
753 break;
754 }
755
756 case GFX_TOY_FACTORY:
757 case GFX_BUBBLE_CATCHER:
758 case GFX_TOFFEE_QUARY:
759 SetAnimationFrame(tile, 0);
760 SetIndustryAnimationLoop(tile, 0);
761 break;
762
763 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
764 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
765 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
766 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
767 AddAnimatedTile(tile);
768 break;
769 }
770 }
771
772 static void TileLoopIndustry_BubbleGenerator(TileIndex tile)
773 {
774 static const int8 _bubble_spawn_location[3][4] = {
775 { 11, 0, -4, -14 },
776 { -4, -10, -4, 1 },
777 { 49, 59, 60, 65 },
778 };
779
780 if (_settings_client.sound.ambient) SndPlayTileFx(SND_2E_EXTRACT_AND_POP, tile);
781
782 int dir = Random() & 3;
783
784 EffectVehicle *v = CreateEffectVehicleAbove(
785 TileX(tile) * TILE_SIZE + _bubble_spawn_location[0][dir],
786 TileY(tile) * TILE_SIZE + _bubble_spawn_location[1][dir],
787 _bubble_spawn_location[2][dir],
788 EV_BUBBLE
789 );
790
791 if (v != NULL) v->animation_substate = dir;
792 }
793
794 static void TileLoop_Industry(TileIndex tile)
795 {
796 if (IsTileOnWater(tile)) TileLoop_Water(tile);
797
798 /* Normally this doesn't happen, but if an industry NewGRF is removed
799 * an industry that was previously build on water can now be flooded.
800 * If this happens the tile is no longer an industry tile after
801 * returning from TileLoop_Water. */
802 if (!IsTileType(tile, MP_INDUSTRY)) return;
803
804 TriggerIndustryTile(tile, INDTILE_TRIGGER_TILE_LOOP);
805
806 if (!IsIndustryCompleted(tile)) {
807 MakeIndustryTileBigger(tile);
808 return;
809 }
810
811 if (_game_mode == GM_EDITOR) return;
812
813 TransportIndustryGoods(tile);
814
815 if (StartStopIndustryTileAnimation(tile, IAT_TILELOOP)) return;
816
817 IndustryGfx newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_next;
818 if (newgfx != INDUSTRYTILE_NOANIM) {
819 ResetIndustryConstructionStage(tile);
820 SetIndustryGfx(tile, newgfx);
821 MarkTileDirtyByTile(tile);
822 return;
823 }
824
825 IndustryGfx gfx = GetIndustryGfx(tile);
826 switch (gfx) {
827 case GFX_COAL_MINE_TOWER_NOT_ANIMATED:
828 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED:
829 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED:
830 if (!(_tick_counter & 0x400) && Chance16(1, 2)) {
831 switch (gfx) {
832 case GFX_COAL_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COAL_MINE_TOWER_ANIMATED; break;
833 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_ANIMATED; break;
834 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_ANIMATED; break;
835 }
836 SetIndustryGfx(tile, gfx);
837 SetAnimationFrame(tile, 0x80);
838 AddAnimatedTile(tile);
839 }
840 break;
841
842 case GFX_OILWELL_NOT_ANIMATED:
843 if (Chance16(1, 6)) {
844 SetIndustryGfx(tile, GFX_OILWELL_ANIMATED_1);
845 SetAnimationFrame(tile, 0);
846 AddAnimatedTile(tile);
847 }
848 break;
849
850 case GFX_COAL_MINE_TOWER_ANIMATED:
851 case GFX_COPPER_MINE_TOWER_ANIMATED:
852 case GFX_GOLD_MINE_TOWER_ANIMATED:
853 if (!(_tick_counter & 0x400)) {
854 switch (gfx) {
855 case GFX_COAL_MINE_TOWER_ANIMATED: gfx = GFX_COAL_MINE_TOWER_NOT_ANIMATED; break;
856 case GFX_COPPER_MINE_TOWER_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_NOT_ANIMATED; break;
857 case GFX_GOLD_MINE_TOWER_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_NOT_ANIMATED; break;
858 }
859 SetIndustryGfx(tile, gfx);
860 SetIndustryCompleted(tile);
861 SetIndustryConstructionStage(tile, 3);
862 DeleteAnimatedTile(tile);
863 }
864 break;
865
866 case GFX_POWERPLANT_SPARKS:
867 if (Chance16(1, 3)) {
868 if (_settings_client.sound.ambient) SndPlayTileFx(SND_0C_ELECTRIC_SPARK, tile);
869 AddAnimatedTile(tile);
870 }
871 break;
872
873 case GFX_COPPER_MINE_CHIMNEY:
874 CreateEffectVehicleAbove(TileX(tile) * TILE_SIZE + 6, TileY(tile) * TILE_SIZE + 6, 43, EV_COPPER_MINE_SMOKE);
875 break;
876
877
878 case GFX_TOY_FACTORY: {
879 Industry *i = Industry::GetByTile(tile);
880 if (i->was_cargo_delivered) {
881 i->was_cargo_delivered = false;
882 SetIndustryAnimationLoop(tile, 0);
883 AddAnimatedTile(tile);
884 }
885 }
886 break;
887
888 case GFX_BUBBLE_GENERATOR:
889 TileLoopIndustry_BubbleGenerator(tile);
890 break;
891
892 case GFX_TOFFEE_QUARY:
893 AddAnimatedTile(tile);
894 break;
895
896 case GFX_SUGAR_MINE_SIEVE:
897 if (Chance16(1, 3)) AddAnimatedTile(tile);
898 break;
899 }
900 }
901
902 static bool ClickTile_Industry(TileIndex tile)
903 {
904 ShowIndustryViewWindow(GetIndustryIndex(tile));
905 return true;
906 }
907
908 static TrackStatus GetTileTrackStatus_Industry(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
909 {
910 return 0;
911 }
912
913 static void ChangeTileOwner_Industry(TileIndex tile, Owner old_owner, Owner new_owner)
914 {
915 /* If the founder merges, the industry was created by the merged company */
916 Industry *i = Industry::GetByTile(tile);
917 if (i->founder == old_owner) i->founder = (new_owner == INVALID_OWNER) ? OWNER_NONE : new_owner;
918 }
919
925 bool IsTileForestIndustry(TileIndex tile)
926 {
927 /* Check for industry tile */
928 if (!IsTileType(tile, MP_INDUSTRY)) return false;
929
930 const Industry *ind = Industry::GetByTile(tile);
931
932 /* Check for organic industry (i.e. not processing or extractive) */
933 if ((GetIndustrySpec(ind->type)->life_type & INDUSTRYLIFE_ORGANIC) == 0) return false;
934
935 /* Check for wood production */
936 for (uint i = 0; i < lengthof(ind->produced_cargo); i++) {
937 /* The industry produces wood. */
938 if (ind->produced_cargo[i] != CT_INVALID && CargoSpec::Get(ind->produced_cargo[i])->label == 'WOOD') return true;
939 }
940
941 return false;
942 }
943
944 static const byte _plantfarmfield_type[] = {1, 1, 1, 1, 1, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6};
945
953 static bool IsSuitableForFarmField(TileIndex tile, bool allow_fields)
954 {
955 switch (GetTileType(tile)) {
956 case MP_CLEAR: return !IsClearGround(tile, CLEAR_SNOW) && !IsClearGround(tile, CLEAR_DESERT) && (allow_fields || !IsClearGround(tile, CLEAR_FIELDS));
957 case MP_TREES: return GetTreeGround(tile) != TREE_GROUND_SHORE;
958 default: return false;
959 }
960 }
961
969 static void SetupFarmFieldFence(TileIndex tile, int size, byte type, DiagDirection side)
970 {
971 TileIndexDiff diff = (DiagDirToAxis(side) == AXIS_Y ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
972
973 do {
974 tile = TILE_MASK(tile);
975
976 if (IsTileType(tile, MP_CLEAR) && IsClearGround(tile, CLEAR_FIELDS)) {
977 byte or_ = type;
978
979 if (or_ == 1 && Chance16(1, 7)) or_ = 2;
980
981 SetFence(tile, side, or_);
982 }
983
984 tile += diff;
985 } while (--size);
986 }
987
988 static void PlantFarmField(TileIndex tile, IndustryID industry)
989 {
990 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
991 if (GetTileZ(tile) + 2 >= GetSnowLine()) return;
992 }
993
994 /* determine field size */
995 uint32 r = (Random() & 0x303) + 0x404;
996 if (_settings_game.game_creation.landscape == LT_ARCTIC) r += 0x404;
997 uint size_x = GB(r, 0, 8);
998 uint size_y = GB(r, 8, 8);
999
1000 TileArea ta(tile - TileDiffXY(min(TileX(tile), size_x / 2), min(TileY(tile), size_y / 2)), size_x, size_y);
1001 ta.ClampToMap();
1002
1003 if (ta.w == 0 || ta.h == 0) return;
1004
1005 /* check the amount of bad tiles */
1006 int count = 0;
1007 TILE_AREA_LOOP(cur_tile, ta) {
1008 assert(cur_tile < MapSize());
1009 count += IsSuitableForFarmField(cur_tile, false);
1010 }
1011 if (count * 2 < ta.w * ta.h) return;
1012
1013 /* determine type of field */
1014 r = Random();
1015 uint counter = GB(r, 5, 3);
1016 uint field_type = GB(r, 8, 8) * 9 >> 8;
1017
1018 /* make field */
1019 TILE_AREA_LOOP(cur_tile, ta) {
1020 assert(cur_tile < MapSize());
1021 if (IsSuitableForFarmField(cur_tile, true)) {
1022 MakeField(cur_tile, field_type, industry);
1023 SetClearCounter(cur_tile, counter);
1024 MarkTileDirtyByTile(cur_tile);
1025 }
1026 }
1027
1028 int type = 3;
1029 if (_settings_game.game_creation.landscape != LT_ARCTIC && _settings_game.game_creation.landscape != LT_TROPIC) {
1030 type = _plantfarmfield_type[Random() & 0xF];
1031 }
1032
1033 SetupFarmFieldFence(ta.tile, ta.h, type, DIAGDIR_NE);
1034 SetupFarmFieldFence(ta.tile, ta.w, type, DIAGDIR_NW);
1035 SetupFarmFieldFence(ta.tile + TileDiffXY(ta.w - 1, 0), ta.h, type, DIAGDIR_SW);
1036 SetupFarmFieldFence(ta.tile + TileDiffXY(0, ta.h - 1), ta.w, type, DIAGDIR_SE);
1037 }
1038
1039 void PlantRandomFarmField(const Industry *i)
1040 {
1041 int x = i->location.w / 2 + Random() % 31 - 16;
1042 int y = i->location.h / 2 + Random() % 31 - 16;
1043
1044 TileIndex tile = TileAddWrap(i->location.tile, x, y);
1045
1046 if (tile != INVALID_TILE) PlantFarmField(tile, i->index);
1047 }
1048
1055 static bool SearchLumberMillTrees(TileIndex tile, void *user_data)
1056 {
1057 if (IsTileType(tile, MP_TREES) && GetTreeGrowth(tile) > 2) {
1058 /* found a tree */
1059
1060 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
1061
1062 _industry_sound_ctr = 1;
1063 _industry_sound_tile = tile;
1064 if (_settings_client.sound.ambient) SndPlayTileFx(SND_38_CHAINSAW, tile);
1065
1066 DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
1067
1068 cur_company.Restore();
1069 return true;
1070 }
1071 return false;
1072 }
1073
1078 static void ChopLumberMillTrees(Industry *i)
1079 {
1080 /* We only want to cut trees if all tiles are completed. */
1081 TILE_AREA_LOOP(tile_cur, i->location) {
1082 if (i->TileBelongsToIndustry(tile_cur)) {
1083 if (!IsIndustryCompleted(tile_cur)) return;
1084 }
1085 }
1086
1087 TileIndex tile = i->location.tile;
1088 if (CircularTileSearch(&tile, 40, SearchLumberMillTrees, NULL)) { // 40x40 tiles to search.
1089 i->produced_cargo_waiting[0] = min(0xffff, i->produced_cargo_waiting[0] + 45); // Found a tree, add according value to waiting cargo.
1090 }
1091 }
1092
1093 static void ProduceIndustryGoods(Industry *i)
1094 {
1095 const IndustrySpec *indsp = GetIndustrySpec(i->type);
1096
1097 /* play a sound? */
1098 if ((i->counter & 0x3F) == 0) {
1099 uint32 r;
1100 uint num;
1101 if (Chance16R(1, 14, r) && (num = indsp->number_of_sounds) != 0 && _settings_client.sound.ambient) {
1102 SndPlayTileFx(
1103 (SoundFx)(indsp->random_sounds[((r >> 16) * num) >> 16]),
1104 i->location.tile);
1105 }
1106 }
1107
1108 i->counter--;
1109
1110 /* produce some cargo */
1111 if ((i->counter % INDUSTRY_PRODUCE_TICKS) == 0) {
1112 if (HasBit(indsp->callback_mask, CBM_IND_PRODUCTION_256_TICKS)) IndustryProductionCallback(i, 1);
1113
1114 IndustryBehaviour indbehav = indsp->behaviour;
1115 i->produced_cargo_waiting[0] = min(0xffff, i->produced_cargo_waiting[0] + i->production_rate[0]);
1116 i->produced_cargo_waiting[1] = min(0xffff, i->produced_cargo_waiting[1] + i->production_rate[1]);
1117
1118 if ((indbehav & INDUSTRYBEH_PLANT_FIELDS) != 0) {
1119 uint16 cb_res = CALLBACK_FAILED;
1120 if (HasBit(indsp->callback_mask, CBM_IND_SPECIAL_EFFECT)) {
1121 cb_res = GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 0, i, i->type, i->location.tile);
1122 }
1123
1124 bool plant;
1125 if (cb_res != CALLBACK_FAILED) {
1126 plant = ConvertBooleanCallback(indsp->grf_prop.grffile, CBID_INDUSTRY_SPECIAL_EFFECT, cb_res);
1127 } else {
1128 plant = Chance16(1, 8);
1129 }
1130
1131 if (plant) PlantRandomFarmField(i);
1132 }
1133 if ((indbehav & INDUSTRYBEH_CUT_TREES) != 0) {
1134 uint16 cb_res = CALLBACK_FAILED;
1135 if (HasBit(indsp->callback_mask, CBM_IND_SPECIAL_EFFECT)) {
1136 cb_res = GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 1, i, i->type, i->location.tile);
1137 }
1138
1139 bool cut;
1140 if (cb_res != CALLBACK_FAILED) {
1141 cut = ConvertBooleanCallback(indsp->grf_prop.grffile, CBID_INDUSTRY_SPECIAL_EFFECT, cb_res);
1142 } else {
1143 cut = ((i->counter % INDUSTRY_CUT_TREE_TICKS) == 0);
1144 }
1145
1146 if (cut) ChopLumberMillTrees(i);
1147 }
1148
1149 TriggerIndustry(i, INDUSTRY_TRIGGER_INDUSTRY_TICK);
1150 StartStopIndustryTileAnimation(i, IAT_INDUSTRY_TICK);
1151 }
1152 }
1153
1154 void OnTick_Industry()
1155 {
1156 if (_industry_sound_ctr != 0) {
1157 _industry_sound_ctr++;
1158
1159 if (_industry_sound_ctr == 75) {
1160 if (_settings_client.sound.ambient) SndPlayTileFx(SND_37_BALLOON_SQUEAK, _industry_sound_tile);
1161 } else if (_industry_sound_ctr == 160) {
1162 _industry_sound_ctr = 0;
1163 if (_settings_client.sound.ambient) SndPlayTileFx(SND_36_CARTOON_CRASH, _industry_sound_tile);
1164 }
1165 }
1166
1167 if (_game_mode == GM_EDITOR) return;
1168
1169 Industry *i;
1170 FOR_ALL_INDUSTRIES(i) {
1171 ProduceIndustryGoods(i);
1172 }
1173 }
1174
1180 static CommandCost CheckNewIndustry_NULL(TileIndex tile)
1181 {
1182 return CommandCost();
1183 }
1184
1190 static CommandCost CheckNewIndustry_Forest(TileIndex tile)
1191 {
1192 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
1193 if (GetTileZ(tile) < HighestSnowLine() + 2) {
1194 return_cmd_error(STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED);
1195 }
1196 }
1197 return CommandCost();
1198 }
1199
1205 static CommandCost CheckNewIndustry_OilRefinery(TileIndex tile)
1206 {
1207 if (_game_mode == GM_EDITOR) return CommandCost();
1208 if (DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _settings_game.game_creation.oil_refinery_limit) return CommandCost();
1209
1210 return_cmd_error(STR_ERROR_CAN_ONLY_BE_POSITIONED);
1211 }
1212
1213 extern bool _ignore_restrictions;
1214
1220 static CommandCost CheckNewIndustry_OilRig(TileIndex tile)
1221 {
1222 if (_game_mode == GM_EDITOR && _ignore_restrictions) return CommandCost();
1223 if (TileHeight(tile) == 0 &&
1224 DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _settings_game.game_creation.oil_refinery_limit) return CommandCost();
1225
1226 return_cmd_error(STR_ERROR_CAN_ONLY_BE_POSITIONED);
1227 }
1228
1234 static CommandCost CheckNewIndustry_Farm(TileIndex tile)
1235 {
1236 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
1237 if (GetTileZ(tile) + 2 >= HighestSnowLine()) {
1238 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1239 }
1240 }
1241 return CommandCost();
1242 }
1243
1249 static CommandCost CheckNewIndustry_Plantation(TileIndex tile)
1250 {
1251 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
1252 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1253 }
1254 return CommandCost();
1255 }
1256
1262 static CommandCost CheckNewIndustry_Water(TileIndex tile)
1263 {
1264 if (GetTropicZone(tile) != TROPICZONE_DESERT) {
1265 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT);
1266 }
1267 return CommandCost();
1268 }
1269
1275 static CommandCost CheckNewIndustry_Lumbermill(TileIndex tile)
1276 {
1277 if (GetTropicZone(tile) != TROPICZONE_RAINFOREST) {
1278 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST);
1279 }
1280 return CommandCost();
1281 }
1282
1288 static CommandCost CheckNewIndustry_BubbleGen(TileIndex tile)
1289 {
1290 if (GetTileZ(tile) > 4) {
1291 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS);
1292 }
1293 return CommandCost();
1294 }
1295
1301 typedef CommandCost CheckNewIndustryProc(TileIndex tile);
1302
1304 static CheckNewIndustryProc * const _check_new_industry_procs[CHECK_END] = {
1305 CheckNewIndustry_NULL,
1306 CheckNewIndustry_Forest,
1307 CheckNewIndustry_OilRefinery,
1308 CheckNewIndustry_Farm,
1309 CheckNewIndustry_Plantation,
1310 CheckNewIndustry_Water,
1311 CheckNewIndustry_Lumbermill,
1312 CheckNewIndustry_BubbleGen,
1313 CheckNewIndustry_OilRig,
1314 };
1315
1326 static CommandCost FindTownForIndustry(TileIndex tile, int type, Town **t)
1327 {
1328 *t = ClosestTownFromTile(tile, UINT_MAX);
1329
1330 if (_settings_game.economy.multiple_industry_per_town) return CommandCost();
1331
1332 const Industry *i;
1333 FOR_ALL_INDUSTRIES(i) {
1334 if (i->type == (byte)type && i->town == *t) {
1335 *t = NULL;
1336 return_cmd_error(STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN);
1337 }
1338 }
1339
1340 return CommandCost();
1341 }
1342
1343 bool IsSlopeRefused(Slope current, Slope refused)
1344 {
1345 if (IsSteepSlope(current)) return true;
1346 if (current != SLOPE_FLAT) {
1347 if (IsSteepSlope(refused)) return true;
1348
1349 Slope t = ComplementSlope(current);
1350
1351 if ((refused & SLOPE_W) && (t & SLOPE_NW)) return true;
1352 if ((refused & SLOPE_S) && (t & SLOPE_NE)) return true;
1353 if ((refused & SLOPE_E) && (t & SLOPE_SW)) return true;
1354 if ((refused & SLOPE_N) && (t & SLOPE_SE)) return true;
1355 }
1356
1357 return false;
1358 }
1359
1372 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)
1373 {
1374 bool refused_slope = false;
1375 bool custom_shape = false;
1376
1377 do {
1378 IndustryGfx gfx = GetTranslatedIndustryTileID(it->gfx);
1379 TileIndex cur_tile = TileAddWrap(tile, it->ti.x, it->ti.y);
1380
1381 if (!IsValidTile(cur_tile)) {
1382 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1383 }
1384
1385 if (gfx == GFX_WATERTILE_SPECIALCHECK) {
1386 if (!IsWaterTile(cur_tile) ||
1387 !IsTileFlat(cur_tile)) {
1388 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1389 }
1390 } else {
1391 CommandCost ret = EnsureNoVehicleOnGround(cur_tile);
1392 if (ret.Failed()) return ret;
1393 if (IsBridgeAbove(cur_tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1394
1395 const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
1396
1397 IndustryBehaviour ind_behav = GetIndustrySpec(type)->behaviour;
1398
1399 /* Perform land/water check if not disabled */
1400 if (!HasBit(its->slopes_refused, 5) && ((HasTileWaterClass(cur_tile) && IsTileOnWater(cur_tile)) == !(ind_behav & INDUSTRYBEH_BUILT_ONWATER))) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1401
1402 if (HasBit(its->callback_mask, CBM_INDT_SHAPE_CHECK)) {
1403 custom_shape = true;
1404 CommandCost ret = PerformIndustryTileSlopeCheck(tile, cur_tile, its, type, gfx, itspec_index, initial_random_bits, founder, creation_type);
1405 if (ret.Failed()) return ret;
1406 } else {
1407 Slope tileh = GetTileSlope(cur_tile);
1408 refused_slope |= IsSlopeRefused(tileh, its->slopes_refused);
1409 }
1410
1411 if ((ind_behav & (INDUSTRYBEH_ONLY_INTOWN | INDUSTRYBEH_TOWN1200_MORE)) || // Tile must be a house
1412 ((ind_behav & INDUSTRYBEH_ONLY_NEARTOWN) && IsTileType(cur_tile, MP_HOUSE))) { // Tile is allowed to be a house (and it is a house)
1413 if (!IsTileType(cur_tile, MP_HOUSE)) {
1414 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS);
1415 }
1416
1417 /* Clear the tiles as OWNER_TOWN to not affect town rating, and to not clear protected buildings */
1418 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
1419 CommandCost ret = DoCommand(cur_tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR);
1420 cur_company.Restore();
1421
1422 if (ret.Failed()) return ret;
1423 } else {
1424 /* Clear the tiles, but do not affect town ratings */
1425 CommandCost ret = DoCommand(cur_tile, 0, 0, DC_AUTO | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR);
1426
1427 if (ret.Failed()) return ret;
1428 }
1429 }
1430 } while ((++it)->ti.x != -0x80);
1431
1432 if (custom_shape_check != NULL) *custom_shape_check = custom_shape;
1433
1434 /* It is almost impossible to have a fully flat land in TG, so what we
1435 * do is that we check if we can make the land flat later on. See
1436 * CheckIfCanLevelIndustryPlatform(). */
1437 if (!refused_slope || (_settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world && !custom_shape && !_ignore_restrictions)) {
1438 return CommandCost();
1439 }
1440 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1441 }
1442
1450 static CommandCost CheckIfIndustryIsAllowed(TileIndex tile, int type, const Town *t)
1451 {
1452 if ((GetIndustrySpec(type)->behaviour & INDUSTRYBEH_TOWN1200_MORE) && t->cache.population < 1200) {
1453 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200);
1454 }
1455
1456 if ((GetIndustrySpec(type)->behaviour & INDUSTRYBEH_ONLY_NEARTOWN) && DistanceMax(t->xy, tile) > 9) {
1457 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER);
1458 }
1459
1460 return CommandCost();
1461 }
1462
1463 static bool CheckCanTerraformSurroundingTiles(TileIndex tile, uint height, int internal)
1464 {
1465 /* Check if we don't leave the map */
1466 if (TileX(tile) == 0 || TileY(tile) == 0 || GetTileType(tile) == MP_VOID) return false;
1467
1468 TileArea ta(tile - TileDiffXY(1, 1), 2, 2);
1469 TILE_AREA_LOOP(tile_walk, ta) {
1470 uint curh = TileHeight(tile_walk);
1471 /* Is the tile clear? */
1472 if ((GetTileType(tile_walk) != MP_CLEAR) && (GetTileType(tile_walk) != MP_TREES)) return false;
1473
1474 /* Don't allow too big of a change if this is the sub-tile check */
1475 if (internal != 0 && Delta(curh, height) > 1) return false;
1476
1477 /* Different height, so the surrounding tiles of this tile
1478 * has to be correct too (in level, or almost in level)
1479 * else you get a chain-reaction of terraforming. */
1480 if (internal == 0 && curh != height) {
1481 if (TileX(tile_walk) == 0 || TileY(tile_walk) == 0 || !CheckCanTerraformSurroundingTiles(tile_walk + TileDiffXY(-1, -1), height, internal + 1)) {
1482 return false;
1483 }
1484 }
1485 }
1486
1487 return true;
1488 }
1489
1494 static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, DoCommandFlag flags, const IndustryTileTable *it, int type)
1495 {
1496 const int MKEND = -0x80; // used for last element in an IndustryTileTable (see build_industry.h)
1497 int max_x = 0;
1498 int max_y = 0;
1499
1500 /* Finds dimensions of largest variant of this industry */
1501 do {
1502 if (it->gfx == 0xFF) continue; // FF been a marquer for a check on clear water, skip it
1503 if (it->ti.x > max_x) max_x = it->ti.x;
1504 if (it->ti.y > max_y) max_y = it->ti.y;
1505 } while ((++it)->ti.x != MKEND);
1506
1507 /* Remember level height */
1508 uint h = TileHeight(tile);
1509
1510 if (TileX(tile) <= _settings_game.construction.industry_platform + 1U || TileY(tile) <= _settings_game.construction.industry_platform + 1U) return false;
1511 /* Check that all tiles in area and surrounding are clear
1512 * this determines that there are no obstructing items */
1513
1514 TileArea ta(tile + TileDiffXY(-_settings_game.construction.industry_platform, -_settings_game.construction.industry_platform),
1515 max_x + 2 + 2 * _settings_game.construction.industry_platform, max_y + 2 + 2 * _settings_game.construction.industry_platform);
1516
1517 if (TileX(ta.tile) + ta.w >= MapMaxX() || TileY(ta.tile) + ta.h >= MapMaxY()) return false;
1518
1519 /* _current_company is OWNER_NONE for randomly generated industries and in editor, or the company who funded or prospected the industry.
1520 * Perform terraforming as OWNER_TOWN to disable autoslope and town ratings. */
1521 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
1522
1523 TILE_AREA_LOOP(tile_walk, ta) {
1524 uint curh = TileHeight(tile_walk);
1525 if (curh != h) {
1526 /* This tile needs terraforming. Check if we can do that without
1527 * damaging the surroundings too much. */
1528 if (!CheckCanTerraformSurroundingTiles(tile_walk, h, 0)) {
1529 cur_company.Restore();
1530 return false;
1531 }
1532 /* This is not 100% correct check, but the best we can do without modifying the map.
1533 * What is missing, is if the difference in height is more than 1.. */
1534 if (DoCommand(tile_walk, SLOPE_N, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND).Failed()) {
1535 cur_company.Restore();
1536 return false;
1537 }
1538 }
1539 }
1540
1541 if (flags & DC_EXEC) {
1542 /* Terraform the land under the industry */
1543 TILE_AREA_LOOP(tile_walk, ta) {
1544 uint curh = TileHeight(tile_walk);
1545 while (curh != h) {
1546 /* We give the terraforming for free here, because we can't calculate
1547 * exact cost in the test-round, and as we all know, that will cause
1548 * a nice assert if they don't match ;) */
1549 DoCommand(tile_walk, SLOPE_N, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND);
1550 curh += (curh > h) ? -1 : 1;
1551 }
1552 }
1553 }
1554
1555 cur_company.Restore();
1556 return true;
1557 }
1558
1559
1566 static CommandCost CheckIfFarEnoughFromConflictingIndustry(TileIndex tile, int type)
1567 {
1568 const IndustrySpec *indspec = GetIndustrySpec(type);
1569 const Industry *i = NULL;
1570
1571 /* On a large map with many industries, it may be faster to check an area. */
1572 static const int dmax = 14;
1573 if (Industry::GetNumItems() > (size_t) (dmax * dmax * 2)) {
1574 const int tx = TileX(tile);
1575 const int ty = TileY(tile);
1576 TileArea tile_area = TileArea(TileXY(max(0, tx - dmax), max(0, ty - dmax)), TileXY(min(MapMaxX(), tx + dmax), min(MapMaxY(), ty + dmax)));
1577 TILE_AREA_LOOP(atile, tile_area) {
1578 if (GetTileType(atile) == MP_INDUSTRY) {
1579 const Industry *i2 = Industry::GetByTile(atile);
1580 if (i == i2) continue;
1581 i = i2;
1582 if (DistanceMax(tile, i->location.tile) > (uint)dmax) continue;
1583 if (i->type == indspec->conflicting[0] ||
1584 i->type == indspec->conflicting[1] ||
1585 i->type == indspec->conflicting[2]) {
1586 return_cmd_error(STR_ERROR_INDUSTRY_TOO_CLOSE);
1587 }
1588 }
1589 }
1590 return CommandCost();
1591 }
1592
1593 FOR_ALL_INDUSTRIES(i) {
1594 /* Within 14 tiles from another industry is considered close */
1595 if (DistanceMax(tile, i->location.tile) > 14) continue;
1596
1597 /* check if there are any conflicting industry types around */
1598 if (i->type == indspec->conflicting[0] ||
1599 i->type == indspec->conflicting[1] ||
1600 i->type == indspec->conflicting[2]) {
1601 return_cmd_error(STR_ERROR_INDUSTRY_TOO_CLOSE);
1602 }
1603 }
1604 return CommandCost();
1605 }
1606
1611 static void AdvertiseIndustryOpening(const Industry *ind)
1612 {
1613 const IndustrySpec *ind_spc = GetIndustrySpec(ind->type);
1614 SetDParam(0, ind_spc->name);
1615 if (ind_spc->new_industry_text > STR_LAST_STRINGID) {
1616 SetDParam(1, STR_TOWN_NAME);
1617 SetDParam(2, ind->town->index);
1618 } else {
1619 SetDParam(1, ind->town->index);
1620 }
1621 AddIndustryNewsItem(ind_spc->new_industry_text, NT_INDUSTRY_OPEN, ind->index);
1622 AI::BroadcastNewEvent(new ScriptEventIndustryOpen(ind->index));
1623 Game::NewEvent(new ScriptEventIndustryOpen(ind->index));
1624 }
1625
1637 static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, const IndustryTileTable *it, byte layout, Town *t, Owner founder, uint16 initial_random_bits)
1638 {
1639 const IndustrySpec *indspec = GetIndustrySpec(type);
1640
1641 i->location = TileArea(tile, 1, 1);
1642 i->type = type;
1643 Industry::IncIndustryTypeCount(type);
1644
1645 i->produced_cargo[0] = indspec->produced_cargo[0];
1646 i->produced_cargo[1] = indspec->produced_cargo[1];
1647 i->accepts_cargo[0] = indspec->accepts_cargo[0];
1648 i->accepts_cargo[1] = indspec->accepts_cargo[1];
1649 i->accepts_cargo[2] = indspec->accepts_cargo[2];
1650 i->production_rate[0] = indspec->production_rate[0];
1651 i->production_rate[1] = indspec->production_rate[1];
1652
1653 /* don't use smooth economy for industries using production related callbacks */
1654 if (indspec->UsesSmoothEconomy()) {
1655 i->production_rate[0] = min((RandomRange(256) + 128) * i->production_rate[0] >> 8, 255);
1656 i->production_rate[1] = min((RandomRange(256) + 128) * i->production_rate[1] >> 8, 255);
1657 }
1658
1659 i->town = t;
1660 i->owner = OWNER_NONE;
1661
1662 uint16 r = Random();
1663 i->random_colour = GB(r, 0, 4);
1664 i->counter = GB(r, 4, 12);
1665 i->random = initial_random_bits;
1666 i->produced_cargo_waiting[0] = 0;
1667 i->produced_cargo_waiting[1] = 0;
1668 i->incoming_cargo_waiting[0] = 0;
1669 i->incoming_cargo_waiting[1] = 0;
1670 i->incoming_cargo_waiting[2] = 0;
1671 i->this_month_production[0] = 0;
1672 i->this_month_production[1] = 0;
1673 i->this_month_transported[0] = 0;
1674 i->this_month_transported[1] = 0;
1675 i->last_month_pct_transported[0] = 0;
1676 i->last_month_pct_transported[1] = 0;
1677 i->last_month_transported[0] = 0;
1678 i->last_month_transported[1] = 0;
1679 i->was_cargo_delivered = false;
1680 i->last_prod_year = _cur_year;
1681 i->founder = founder;
1682
1683 i->construction_date = _date;
1684 i->construction_type = (_game_mode == GM_EDITOR) ? ICT_SCENARIO_EDITOR :
1685 (_generating_world ? ICT_MAP_GENERATION : ICT_NORMAL_GAMEPLAY);
1686
1687 /* Adding 1 here makes it conform to specs of var44 of varaction2 for industries
1688 * 0 = created prior of newindustries
1689 * else, chosen layout + 1 */
1690 i->selected_layout = layout + 1;
1691
1692 i->prod_level = PRODLEVEL_DEFAULT;
1693
1694 /* Call callbacks after the regular fields got initialised. */
1695
1696 if (HasBit(indspec->callback_mask, CBM_IND_PROD_CHANGE_BUILD)) {
1697 uint16 res = GetIndustryCallback(CBID_INDUSTRY_PROD_CHANGE_BUILD, 0, Random(), i, type, INVALID_TILE);
1698 if (res != CALLBACK_FAILED) {
1699 if (res < PRODLEVEL_MINIMUM || res > PRODLEVEL_MAXIMUM) {
1700 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_PROD_CHANGE_BUILD, res);
1701 } else {
1702 i->prod_level = res;
1703 i->RecomputeProductionMultipliers();
1704 }
1705 }
1706 }
1707
1708 if (_generating_world) {
1709 i->last_month_production[0] = i->production_rate[0] * 8;
1710 i->last_month_production[1] = i->production_rate[1] * 8;
1711 } else {
1712 i->last_month_production[0] = i->last_month_production[1] = 0;
1713 }
1714
1715 if (HasBit(indspec->callback_mask, CBM_IND_DECIDE_COLOUR)) {
1716 uint16 res = GetIndustryCallback(CBID_INDUSTRY_DECIDE_COLOUR, 0, 0, i, type, INVALID_TILE);
1717 if (res != CALLBACK_FAILED) {
1718 if (GB(res, 4, 11) != 0) ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_DECIDE_COLOUR, res);
1719 i->random_colour = GB(res, 0, 4);
1720 }
1721 }
1722
1723 if (HasBit(indspec->callback_mask, CBM_IND_INPUT_CARGO_TYPES)) {
1724 for (uint j = 0; j < lengthof(i->accepts_cargo); j++) i->accepts_cargo[j] = CT_INVALID;
1725 for (uint j = 0; j < lengthof(i->accepts_cargo); j++) {
1726 uint16 res = GetIndustryCallback(CBID_INDUSTRY_INPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE);
1727 if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
1728 if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
1729 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_INPUT_CARGO_TYPES, res);
1730 break;
1731 }
1732 i->accepts_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
1733 }
1734 }
1735
1736 if (HasBit(indspec->callback_mask, CBM_IND_OUTPUT_CARGO_TYPES)) {
1737 for (uint j = 0; j < lengthof(i->produced_cargo); j++) i->produced_cargo[j] = CT_INVALID;
1738 for (uint j = 0; j < lengthof(i->produced_cargo); j++) {
1739 uint16 res = GetIndustryCallback(CBID_INDUSTRY_OUTPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE);
1740 if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
1741 if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
1742 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_OUTPUT_CARGO_TYPES, res);
1743 break;
1744 }
1745 i->produced_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
1746 }
1747 }
1748
1749 /* Plant the tiles */
1750
1751 do {
1752 TileIndex cur_tile = tile + ToTileIndexDiff(it->ti);
1753
1754 if (it->gfx != GFX_WATERTILE_SPECIALCHECK) {
1755 i->location.Add(cur_tile);
1756
1757 WaterClass wc = (IsWaterTile(cur_tile) ? GetWaterClass(cur_tile) : WATER_CLASS_INVALID);
1758
1759 DoCommand(cur_tile, 0, 0, DC_EXEC | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR);
1760
1761 MakeIndustry(cur_tile, i->index, it->gfx, Random(), wc);
1762
1763 if (_generating_world) {
1764 SetIndustryConstructionCounter(cur_tile, 3);
1765 SetIndustryConstructionStage(cur_tile, 2);
1766 }
1767
1768 /* it->gfx is stored in the map. But the translated ID cur_gfx is the interesting one */
1769 IndustryGfx cur_gfx = GetTranslatedIndustryTileID(it->gfx);
1770 const IndustryTileSpec *its = GetIndustryTileSpec(cur_gfx);
1771 if (its->animation.status != ANIM_STATUS_NO_ANIMATION) AddAnimatedTile(cur_tile);
1772 }
1773 } while ((++it)->ti.x != -0x80);
1774
1775 if (GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_PLANT_ON_BUILT) {
1776 for (uint j = 0; j != 50; j++) PlantRandomFarmField(i);
1777 }
1778 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0);
1779
1780 Station::RecomputeIndustriesNearForAll();
1781 }
1782
1799 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)
1800 {
1801 assert(itspec_index < indspec->num_table);
1802 const IndustryTileTable *it = indspec->table[itspec_index];
1803 bool custom_shape_check = false;
1804
1805 *ip = NULL;
1806
1807 SmallVector<ClearedObjectArea, 1> object_areas(_cleared_object_areas);
1808 CommandCost ret = CheckIfIndustryTilesAreFree(tile, it, itspec_index, type, random_initial_bits, founder, creation_type, &custom_shape_check);
1809 _cleared_object_areas = object_areas;
1810 if (ret.Failed()) return ret;
1811
1812 if (HasBit(GetIndustrySpec(type)->callback_mask, CBM_IND_LOCATION)) {
1813 ret = CheckIfCallBackAllowsCreation(tile, type, itspec_index, random_var8f, random_initial_bits, founder, creation_type);
1814 } else {
1815 ret = _check_new_industry_procs[indspec->check_proc](tile);
1816 }
1817 if (ret.Failed()) return ret;
1818
1819 if (!custom_shape_check && _settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world &&
1820 !_ignore_restrictions && !CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER, it, type)) {
1821 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1822 }
1823
1824 ret = CheckIfFarEnoughFromConflictingIndustry(tile, type);
1825 if (ret.Failed()) return ret;
1826
1827 Town *t = NULL;
1828 ret = FindTownForIndustry(tile, type, &t);
1829 if (ret.Failed()) return ret;
1830 assert(t != NULL);
1831
1832 ret = CheckIfIndustryIsAllowed(tile, type, t);
1833 if (ret.Failed()) return ret;
1834
1835 if (!Industry::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_INDUSTRIES);
1836
1837 if (flags & DC_EXEC) {
1838 *ip = new Industry(tile);
1839 if (!custom_shape_check) CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER | DC_EXEC, it, type);
1840 DoCreateNewIndustry(*ip, tile, type, it, itspec_index, t, founder, random_initial_bits);
1841 }
1842
1843 return CommandCost();
1844 }
1845
1858 CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1859 {
1860 IndustryType it = GB(p1, 0, 8);
1861 if (it >= NUM_INDUSTRYTYPES) return CMD_ERROR;
1862
1863 const IndustrySpec *indspec = GetIndustrySpec(it);
1864
1865 /* Check if the to-be built/founded industry is available for this climate. */
1866 if (!indspec->enabled || indspec->num_table == 0) return CMD_ERROR;
1867
1868 /* If the setting for raw-material industries is not on, you cannot build raw-material industries.
1869 * Raw material industries are industries that do not accept cargo (at least for now) */
1870 if (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 0 && indspec->IsRawIndustry()) {
1871 return CMD_ERROR;
1872 }
1873
1874 if (_game_mode != GM_EDITOR && GetIndustryProbabilityCallback(it, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, 1) == 0) {
1875 return CMD_ERROR;
1876 }
1877
1878 Randomizer randomizer;
1879 randomizer.SetSeed(p2);
1880 uint16 random_initial_bits = GB(p2, 0, 16);
1881 uint32 random_var8f = randomizer.Next();
1882 int num_layouts = indspec->num_table;
1883 CommandCost ret = CommandCost(STR_ERROR_SITE_UNSUITABLE);
1884 const bool deity_prospect = _current_company == OWNER_DEITY && !HasBit(p1, 16);
1885
1886 Industry *ind = NULL;
1887 if (deity_prospect || (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 2 && indspec->IsRawIndustry())) {
1888 if (flags & DC_EXEC) {
1889 /* Prospected industries are build as OWNER_TOWN to not e.g. be build on owned land of the founder */
1890 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
1891 /* Prospecting has a chance to fail, however we cannot guarantee that something can
1892 * be built on the map, so the chance gets lower when the map is fuller, but there
1893 * is nothing we can really do about that. */
1894 if (deity_prospect || Random() <= indspec->prospecting_chance) {
1895 for (int i = 0; i < 5000; i++) {
1896 /* We should not have more than one Random() in a function call
1897 * because parameter evaluation order is not guaranteed in the c++ standard
1898 */
1899 tile = RandomTile();
1900 /* Start with a random layout */
1901 int layout = RandomRange(num_layouts);
1902 /* Check now each layout, starting with the random one */
1903 for (int j = 0; j < num_layouts; j++) {
1904 layout = (layout + 1) % num_layouts;
1905 ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, cur_company.GetOriginalValue(), _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_PROSPECTCREATION, &ind);
1906 if (ret.Succeeded()) break;
1907 }
1908 if (ret.Succeeded()) break;
1909 }
1910 }
1911 cur_company.Restore();
1912 }
1913 } else {
1914 int layout = GB(p1, 8, 8);
1915 if (layout >= num_layouts) return CMD_ERROR;
1916
1917 /* Check subsequently each layout, starting with the given layout in p1 */
1918 for (int i = 0; i < num_layouts; i++) {
1919 layout = (layout + 1) % num_layouts;
1920 ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, _current_company, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, &ind);
1921 if (ret.Succeeded()) break;
1922 }
1923
1924 /* If it still failed, there's no suitable layout to build here, return the error */
1925 if (ret.Failed()) return ret;
1926 }
1927
1928 if ((flags & DC_EXEC) && ind != NULL && _game_mode != GM_EDITOR) {
1929 AdvertiseIndustryOpening(ind);
1930 }
1931
1932 return CommandCost(EXPENSES_OTHER, indspec->GetConstructionCost());
1933 }
1934
1935
1943 static Industry *CreateNewIndustry(TileIndex tile, IndustryType type, IndustryAvailabilityCallType creation_type)
1944 {
1945 const IndustrySpec *indspec = GetIndustrySpec(type);
1946
1947 uint32 seed = Random();
1948 uint32 seed2 = Random();
1949 Industry *i = NULL;
1950 CommandCost ret = CreateNewIndustryHelper(tile, type, DC_EXEC, indspec, RandomRange(indspec->num_table), seed, GB(seed2, 0, 16), OWNER_NONE, creation_type, &i);
1951 assert(i != NULL || ret.Failed());
1952 return i;
1953 }
1954
1961 static uint32 GetScaledIndustryGenerationProbability(IndustryType it, bool *force_at_least_one)
1962 {
1963 const IndustrySpec *ind_spc = GetIndustrySpec(it);
1964 uint32 chance = ind_spc->appear_creation[_settings_game.game_creation.landscape] * 16; // * 16 to increase precision
1965 if (!ind_spc->enabled || ind_spc->num_table == 0 ||
1966 (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == ID_FUND_ONLY) ||
1967 (chance = GetIndustryProbabilityCallback(it, IACT_MAPGENERATION, chance)) == 0) {
1968 *force_at_least_one = false;
1969 return 0;
1970 } else {
1971 /* We want industries appearing at coast to appear less often on bigger maps, as length of coast increases slower than map area.
1972 * For simplicity we scale in both cases, though scaling the probabilities of all industries has no effect. */
1973 chance = (ind_spc->check_proc == CHECK_REFINERY || ind_spc->check_proc == CHECK_OIL_RIG) ? ScaleByMapSize1D(chance) : ScaleByMapSize(chance);
1974
1975 *force_at_least_one = (chance > 0) && !(ind_spc->behaviour & INDUSTRYBEH_NOBUILT_MAPCREATION) && (_game_mode != GM_EDITOR);
1976 return chance;
1977 }
1978 }
1979
1986 static uint16 GetIndustryGamePlayProbability(IndustryType it, byte *min_number)
1987 {
1988 if (_settings_game.difficulty.industry_density == ID_FUND_ONLY) {
1989 *min_number = 0;
1990 return 0;
1991 }
1992
1993 const IndustrySpec *ind_spc = GetIndustrySpec(it);
1994 byte chance = ind_spc->appear_ingame[_settings_game.game_creation.landscape];
1995 if (!ind_spc->enabled || ind_spc->num_table == 0 ||
1996 ((ind_spc->behaviour & INDUSTRYBEH_BEFORE_1950) && _cur_year > 1950) ||
1997 ((ind_spc->behaviour & INDUSTRYBEH_AFTER_1960) && _cur_year < 1960) ||
1998 (chance = GetIndustryProbabilityCallback(it, IACT_RANDOMCREATION, chance)) == 0) {
1999 *min_number = 0;
2000 return 0;
2001 }
2002 *min_number = (ind_spc->behaviour & INDUSTRYBEH_CANCLOSE_LASTINSTANCE) ? 1 : 0;
2003 return chance;
2004 }
2005
2010 static uint GetNumberOfIndustries()
2011 {
2012 /* Number of industries on a 256x256 map. */
2013 static const uint16 numof_industry_table[] = {
2014 0, // none
2015 0, // minimal
2016 10, // very low
2017 25, // low
2018 55, // normal
2019 80, // high
2020 };
2021
2022 assert(lengthof(numof_industry_table) == ID_END);
2023 uint difficulty = (_game_mode != GM_EDITOR) ? _settings_game.difficulty.industry_density : (uint)ID_VERY_LOW;
2024 return min(IndustryPool::MAX_SIZE, ScaleByMapSize(numof_industry_table[difficulty]));
2025 }
2026
2035 static Industry *PlaceIndustry(IndustryType type, IndustryAvailabilityCallType creation_type, bool try_hard)
2036 {
2037 uint tries = try_hard ? 10000u : 2000u;
2038 for (; tries > 0; tries--) {
2039 Industry *ind = CreateNewIndustry(RandomTile(), type, creation_type);
2040 if (ind != NULL) return ind;
2041 }
2042 return NULL;
2043 }
2044
2050 static void PlaceInitialIndustry(IndustryType type, bool try_hard)
2051 {
2052 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
2053
2054 IncreaseGeneratingWorldProgress(GWP_INDUSTRY);
2055 PlaceIndustry(type, IACT_MAPGENERATION, try_hard);
2056
2057 cur_company.Restore();
2058 }
2059
2064 static uint GetCurrentTotalNumberOfIndustries()
2065 {
2066 int total = 0;
2067 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) total += Industry::GetIndustryTypeCount(it);
2068 return total;
2069 }
2070
2071
2073 void IndustryTypeBuildData::Reset()
2074 {
2075 this->probability = 0;
2076 this->min_number = 0;
2077 this->target_count = 0;
2078 this->max_wait = 1;
2079 this->wait_count = 0;
2080 }
2081
2083 void IndustryBuildData::Reset()
2084 {
2085 this->wanted_inds = GetCurrentTotalNumberOfIndustries() << 16;
2086
2087 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2088 this->builddata[it].Reset();
2089 }
2090 }
2091
2093 void IndustryBuildData::MonthlyLoop()
2094 {
2095 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.
2096 if (_settings_game.difficulty.industry_density == ID_FUND_ONLY) return; // 'no industries' setting.
2097
2098 /* To prevent running out of unused industries for the player to connect,
2099 * add a fraction of new industries each month, but only if the manager can keep up. */
2100 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).
2101 if (GetCurrentTotalNumberOfIndustries() + max_behind >= (this->wanted_inds >> 16)) {
2102 this->wanted_inds += ScaleByMapSize(NEWINDS_PER_MONTH);
2103 }
2104 }
2105
2110 void GenerateIndustries()
2111 {
2112 if (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == ID_FUND_ONLY) return; // No industries in the game.
2113
2114 uint32 industry_probs[NUM_INDUSTRYTYPES];
2115 bool force_at_least_one[NUM_INDUSTRYTYPES];
2116 uint32 total_prob = 0;
2117 uint num_forced = 0;
2118
2119 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2120 industry_probs[it] = GetScaledIndustryGenerationProbability(it, force_at_least_one + it);
2121 total_prob += industry_probs[it];
2122 if (force_at_least_one[it]) num_forced++;
2123 }
2124
2125 uint total_amount = GetNumberOfIndustries();
2126 if (total_prob == 0 || total_amount < num_forced) {
2127 /* Only place the forced ones */
2128 total_amount = num_forced;
2129 }
2130
2131 SetGeneratingWorldProgress(GWP_INDUSTRY, total_amount);
2132
2133 /* Try to build one industry per type independent of any probabilities */
2134 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2135 if (force_at_least_one[it]) {
2136 assert(total_amount > 0);
2137 total_amount--;
2138 PlaceInitialIndustry(it, true);
2139 }
2140 }
2141
2142 /* Add the remaining industries according to their probabilities */
2143 for (uint i = 0; i < total_amount; i++) {
2144 uint32 r = RandomRange(total_prob);
2145 IndustryType it = 0;
2146 while (r >= industry_probs[it]) {
2147 r -= industry_probs[it];
2148 it++;
2149 assert(it < NUM_INDUSTRYTYPES);
2150 }
2151 assert(industry_probs[it] > 0);
2152 PlaceInitialIndustry(it, false);
2153 }
2154 _industry_builder.Reset();
2155 }
2156
2161 static void UpdateIndustryStatistics(Industry *i)
2162 {
2163 for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
2164 if (i->produced_cargo[j] != CT_INVALID) {
2165 byte pct = 0;
2166 if (i->this_month_production[j] != 0) {
2167 i->last_prod_year = _cur_year;
2168 pct = min(i->this_month_transported[j] * 256 / i->this_month_production[j], 255);
2169 }
2170 i->last_month_pct_transported[j] = pct;
2171
2172 i->last_month_production[j] = i->this_month_production[j];
2173 i->this_month_production[j] = 0;
2174
2175 i->last_month_transported[j] = i->this_month_transported[j];
2176 i->this_month_transported[j] = 0;
2177 }
2178 }
2179 }
2180
2185 void Industry::RecomputeProductionMultipliers()
2186 {
2187 const IndustrySpec *indspec = GetIndustrySpec(this->type);
2188 assert(!indspec->UsesSmoothEconomy());
2189
2190 /* Rates are rounded up, so e.g. oilrig always produces some passengers */
2191 this->production_rate[0] = min(CeilDiv(indspec->production_rate[0] * this->prod_level, PRODLEVEL_DEFAULT), 0xFF);
2192 this->production_rate[1] = min(CeilDiv(indspec->production_rate[1] * this->prod_level, PRODLEVEL_DEFAULT), 0xFF);
2193 }
2194
2195
2201 bool IndustryTypeBuildData::GetIndustryTypeData(IndustryType it)
2202 {
2203 byte min_number;
2204 uint32 probability = GetIndustryGamePlayProbability(it, &min_number);
2205 bool changed = min_number != this->min_number || probability != this->probability;
2206 this->min_number = min_number;
2207 this->probability = probability;
2208 return changed;
2209 }
2210
2212 void IndustryBuildData::SetupTargetCount()
2213 {
2214 bool changed = false;
2215 uint num_planned = 0; // Number of industries planned in the industry build data.
2216 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2217 changed |= this->builddata[it].GetIndustryTypeData(it);
2218 num_planned += this->builddata[it].target_count;
2219 }
2220 uint total_amount = this->wanted_inds >> 16; // Desired total number of industries.
2221 changed |= num_planned != total_amount;
2222 if (!changed) return; // All industries are still the same, no need to re-randomize.
2223
2224 /* Initialize the target counts. */
2225 uint force_build = 0; // Number of industries that should always be available.
2226 uint32 total_prob = 0; // Sum of probabilities.
2227 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2228 IndustryTypeBuildData *ibd = this->builddata + it;
2229 force_build += ibd->min_number;
2230 ibd->target_count = ibd->min_number;
2231 total_prob += ibd->probability;
2232 }
2233
2234 if (total_prob == 0) return; // No buildable industries.
2235
2236 /* Subtract forced industries from the number of industries available for construction. */
2237 total_amount = (total_amount <= force_build) ? 0 : total_amount - force_build;
2238
2239 /* Assign number of industries that should be aimed for, by using the probability as a weight. */
2240 while (total_amount > 0) {
2241 uint32 r = RandomRange(total_prob);
2242 IndustryType it = 0;
2243 while (r >= this->builddata[it].probability) {
2244 r -= this->builddata[it].probability;
2245 it++;
2246 assert(it < NUM_INDUSTRYTYPES);
2247 }
2248 assert(this->builddata[it].probability > 0);
2249 this->builddata[it].target_count++;
2250 total_amount--;
2251 }
2252 }
2253
2257 void IndustryBuildData::TryBuildNewIndustry()
2258 {
2259 this->SetupTargetCount();
2260
2261 int missing = 0; // Number of industries that need to be build.
2262 uint count = 0; // Number of industry types eligible for build.
2263 uint32 total_prob = 0; // Sum of probabilities.
2264 IndustryType forced_build = NUM_INDUSTRYTYPES; // Industry type that should be forcibly build.
2265 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2266 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
2267 missing += difference;
2268 if (this->builddata[it].wait_count > 0) continue; // This type may not be built now.
2269 if (difference > 0) {
2270 if (Industry::GetIndustryTypeCount(it) == 0 && this->builddata[it].min_number > 0) {
2271 /* An industry that should exist at least once, is not available. Force it, trying the most needed one first. */
2272 if (forced_build == NUM_INDUSTRYTYPES ||
2273 difference > this->builddata[forced_build].target_count - Industry::GetIndustryTypeCount(forced_build)) {
2274 forced_build = it;
2275 }
2276 }
2277 total_prob += difference;
2278 count++;
2279 }
2280 }
2281
2282 if (EconomyIsInRecession() || (forced_build == NUM_INDUSTRYTYPES && (missing <= 0 || total_prob == 0))) count = 0; // Skip creation of an industry.
2283
2284 if (count >= 1) {
2285 /* If not forced, pick a weighted random industry to build.
2286 * For the case that count == 1, there is no need to draw a random number. */
2287 IndustryType it;
2288 if (forced_build != NUM_INDUSTRYTYPES) {
2289 it = forced_build;
2290 } else {
2291 /* Non-forced, select an industry type to build (weighted random). */
2292 uint32 r = 0; // Initialized to silence the compiler.
2293 if (count > 1) r = RandomRange(total_prob);
2294 for (it = 0; it < NUM_INDUSTRYTYPES; it++) {
2295 if (this->builddata[it].wait_count > 0) continue; // Type may not be built now.
2296 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
2297 if (difference <= 0) continue; // Too many of this kind.
2298 if (count == 1) break;
2299 if (r < (uint)difference) break;
2300 r -= difference;
2301 }
2302 assert(it < NUM_INDUSTRYTYPES && this->builddata[it].target_count > Industry::GetIndustryTypeCount(it));
2303 }
2304
2305 /* Try to create the industry. */
2306 const Industry *ind = PlaceIndustry(it, IACT_RANDOMCREATION, false);
2307 if (ind == NULL) {
2308 this->builddata[it].wait_count = this->builddata[it].max_wait + 1; // Compensate for decrementing below.
2309 this->builddata[it].max_wait = min(1000, this->builddata[it].max_wait + 2);
2310 } else {
2311 AdvertiseIndustryOpening(ind);
2312 this->builddata[it].max_wait = max(this->builddata[it].max_wait / 2, 1); // Reduce waiting time of the industry type.
2313 }
2314 }
2315
2316 /* Decrement wait counters. */
2317 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2318 if (this->builddata[it].wait_count > 0) this->builddata[it].wait_count--;
2319 }
2320 }
2321
2330 static bool CheckIndustryCloseDownProtection(IndustryType type)
2331 {
2332 const IndustrySpec *indspec = GetIndustrySpec(type);
2333
2334 /* oil wells (or the industries with that flag set) are always allowed to closedown */
2335 if ((indspec->behaviour & INDUSTRYBEH_DONT_INCR_PROD) && _settings_game.game_creation.landscape == LT_TEMPERATE) return false;
2336 return (indspec->behaviour & INDUSTRYBEH_CANCLOSE_LASTINSTANCE) == 0 && Industry::GetIndustryTypeCount(type) <= 1;
2337 }
2338
2348 static void CanCargoServiceIndustry(CargoID cargo, Industry *ind, bool *c_accepts, bool *c_produces)
2349 {
2350 if (cargo == CT_INVALID) return;
2351
2352 /* Check for acceptance of cargo */
2353 for (byte j = 0; j < lengthof(ind->accepts_cargo); j++) {
2354 if (cargo == ind->accepts_cargo[j] && !IndustryTemporarilyRefusesCargo(ind, cargo)) {
2355 *c_accepts = true;
2356 break;
2357 }
2358 }
2359
2360 /* Check for produced cargo */
2361 for (byte j = 0; j < lengthof(ind->produced_cargo); j++) {
2362 if (cargo == ind->produced_cargo[j]) {
2363 *c_produces = true;
2364 break;
2365 }
2366 }
2367 }
2368
2382 static int WhoCanServiceIndustry(Industry *ind)
2383 {
2384 /* Find all stations within reach of the industry */
2385 StationList stations;
2386 FindStationsAroundTiles(ind->location, &stations);
2387
2388 if (stations.Length() == 0) return 0; // No stations found at all => nobody services
2389
2390 const Vehicle *v;
2391 int result = 0;
2392 FOR_ALL_VEHICLES(v) {
2393 /* Is it worthwhile to try this vehicle? */
2394 if (v->owner != _local_company && result != 0) continue;
2395
2396 /* Check whether it accepts the right kind of cargo */
2397 bool c_accepts = false;
2398 bool c_produces = false;
2399 if (v->type == VEH_TRAIN && v->IsFrontEngine()) {
2400 for (const Vehicle *u = v; u != NULL; u = u->Next()) {
2401 CanCargoServiceIndustry(u->cargo_type, ind, &c_accepts, &c_produces);
2402 }
2403 } else if (v->type == VEH_ROAD || v->type == VEH_SHIP || v->type == VEH_AIRCRAFT) {
2404 CanCargoServiceIndustry(v->cargo_type, ind, &c_accepts, &c_produces);
2405 } else {
2406 continue;
2407 }
2408 if (!c_accepts && !c_produces) continue; // Wrong cargo
2409
2410 /* Check orders of the vehicle.
2411 * We cannot check the first of shared orders only, since the first vehicle in such a chain
2412 * may have a different cargo type.
2413 */
2414 const Order *o;
2415 FOR_VEHICLE_ORDERS(v, o) {
2416 if (o->IsType(OT_GOTO_STATION) && !(o->GetUnloadType() & OUFB_TRANSFER)) {
2417 /* Vehicle visits a station to load or unload */
2418 Station *st = Station::Get(o->GetDestination());
2419 assert(st != NULL);
2420
2421 /* Same cargo produced by industry is dropped here => not serviced by vehicle v */
2422 if ((o->GetUnloadType() & OUFB_UNLOAD) && !c_accepts) break;
2423
2424 if (stations.Contains(st)) {
2425 if (v->owner == _local_company) return 2; // Company services industry
2426 result = 1; // Competitor services industry
2427 }
2428 }
2429 }
2430 }
2431 return result;
2432 }
2433
2441 static void ReportNewsProductionChangeIndustry(Industry *ind, CargoID type, int percent)
2442 {
2443 NewsType nt;
2444
2445 switch (WhoCanServiceIndustry(ind)) {
2446 case 0: nt = NT_INDUSTRY_NOBODY; break;
2447 case 1: nt = NT_INDUSTRY_OTHER; break;
2448 case 2: nt = NT_INDUSTRY_COMPANY; break;
2449 default: NOT_REACHED();
2450 }
2451 SetDParam(2, abs(percent));
2452 SetDParam(0, CargoSpec::Get(type)->name);
2453 SetDParam(1, ind->index);
2454 AddIndustryNewsItem(
2455 percent >= 0 ? STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH : STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH,
2456 nt,
2457 ind->index
2458 );
2459 }
2460
2461 static const uint PERCENT_TRANSPORTED_60 = 153;
2462 static const uint PERCENT_TRANSPORTED_80 = 204;
2463
2469 static void ChangeIndustryProduction(Industry *i, bool monthly)
2470 {
2471 StringID str = STR_NULL;
2472 bool closeit = false;
2473 const IndustrySpec *indspec = GetIndustrySpec(i->type);
2474 bool standard = false;
2475 bool suppress_message = false;
2476 bool recalculate_multipliers = false;
2477 /* don't use smooth economy for industries using production related callbacks */
2478 bool smooth_economy = indspec->UsesSmoothEconomy();
2479 byte div = 0;
2480 byte mul = 0;
2481 int8 increment = 0;
2482
2483 bool callback_enabled = HasBit(indspec->callback_mask, monthly ? CBM_IND_MONTHLYPROD_CHANGE : CBM_IND_PRODUCTION_CHANGE);
2484 if (callback_enabled) {
2485 uint16 res = GetIndustryCallback(monthly ? CBID_INDUSTRY_MONTHLYPROD_CHANGE : CBID_INDUSTRY_PRODUCTION_CHANGE, 0, Random(), i, i->type, i->location.tile);
2486 if (res != CALLBACK_FAILED) { // failed callback means "do nothing"
2487 suppress_message = HasBit(res, 7);
2488 /* Get the custom message if any */
2489 if (HasBit(res, 8)) str = MapGRFStringID(indspec->grf_prop.grffile->grfid, GB(GetRegister(0x100), 0, 16));
2490 res = GB(res, 0, 4);
2491 switch (res) {
2492 default: NOT_REACHED();
2493 case 0x0: break; // Do nothing, but show the custom message if any
2494 case 0x1: div = 1; break; // Halve industry production. If production reaches the quarter of the default, the industry is closed instead.
2495 case 0x2: mul = 1; break; // Double industry production if it hasn't reached eight times of the original yet.
2496 case 0x3: closeit = true; break; // The industry announces imminent closure, and is physically removed from the map next month.
2497 case 0x4: standard = true; break; // Do the standard random production change as if this industry was a primary one.
2498 case 0x5: case 0x6: case 0x7: // Divide production by 4, 8, 16
2499 case 0x8: div = res - 0x3; break; // Divide production by 32
2500 case 0x9: case 0xA: case 0xB: // Multiply production by 4, 8, 16
2501 case 0xC: mul = res - 0x7; break; // Multiply production by 32
2502 case 0xD: // decrement production
2503 case 0xE: // increment production
2504 increment = res == 0x0D ? -1 : 1;
2505 break;
2506 case 0xF: // Set production to third byte of register 0x100
2507 i->prod_level = Clamp(GB(GetRegister(0x100), 16, 8), PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
2508 recalculate_multipliers = true;
2509 break;
2510 }
2511 }
2512 } else {
2513 if (monthly != smooth_economy) return;
2514 if (indspec->life_type == INDUSTRYLIFE_BLACK_HOLE) return;
2515 }
2516
2517 if (standard || (!callback_enabled && (indspec->life_type & (INDUSTRYLIFE_ORGANIC | INDUSTRYLIFE_EXTRACTIVE)) != 0)) {
2518 /* decrease or increase */
2519 bool only_decrease = (indspec->behaviour & INDUSTRYBEH_DONT_INCR_PROD) && _settings_game.game_creation.landscape == LT_TEMPERATE;
2520
2521 if (smooth_economy) {
2522 closeit = true;
2523 for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
2524 if (i->produced_cargo[j] == CT_INVALID) continue;
2525 uint32 r = Random();
2526 int old_prod, new_prod, percent;
2527 /* If over 60% is transported, mult is 1, else mult is -1. */
2528 int mult = (i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_60) ? 1 : -1;
2529
2530 new_prod = old_prod = i->production_rate[j];
2531
2532 /* For industries with only_decrease flags (temperate terrain Oil Wells),
2533 * the multiplier will always be -1 so they will only decrease. */
2534 if (only_decrease) {
2535 mult = -1;
2536 /* For normal industries, if over 60% is transported, 33% chance for decrease.
2537 * Bonus for very high station ratings (over 80%): 16% chance for decrease. */
2538 } else if (Chance16I(1, ((i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_80) ? 6 : 3), r)) {
2539 mult *= -1;
2540 }
2541
2542 /* 4.5% chance for 3-23% (or 1 unit for very low productions) production change,
2543 * determined by mult value. If mult = 1 prod. increases, else (-1) it decreases. */
2544 if (Chance16I(1, 22, r >> 16)) {
2545 new_prod += mult * (max(((RandomRange(50) + 10) * old_prod) >> 8, 1U));
2546 }
2547
2548 /* Prevent production to overflow or Oil Rig passengers to be over-"produced" */
2549 new_prod = Clamp(new_prod, 1, 255);
2550
2551 if (((indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0) && j == 1) {
2552 new_prod = Clamp(new_prod, 0, 16);
2553 }
2554
2555 /* Do not stop closing the industry when it has the lowest possible production rate */
2556 if (new_prod == old_prod && old_prod > 1) {
2557 closeit = false;
2558 continue;
2559 }
2560
2561 percent = (old_prod == 0) ? 100 : (new_prod * 100 / old_prod - 100);
2562 i->production_rate[j] = new_prod;
2563
2564 /* Close the industry when it has the lowest possible production rate */
2565 if (new_prod > 1) closeit = false;
2566
2567 if (abs(percent) >= 10) {
2568 ReportNewsProductionChangeIndustry(i, i->produced_cargo[j], percent);
2569 }
2570 }
2571 } else {
2572 if (only_decrease || Chance16(1, 3)) {
2573 /* If more than 60% transported, 66% chance of increase, else 33% chance of increase */
2574 if (!only_decrease && (i->last_month_pct_transported[0] > PERCENT_TRANSPORTED_60) != Chance16(1, 3)) {
2575 mul = 1; // Increase production
2576 } else {
2577 div = 1; // Decrease production
2578 }
2579 }
2580 }
2581 }
2582
2583 if (!callback_enabled && (indspec->life_type & INDUSTRYLIFE_PROCESSING)) {
2584 if ( (byte)(_cur_year - i->last_prod_year) >= 5 && Chance16(1, smooth_economy ? 180 : 2)) {
2585 closeit = true;
2586 }
2587 }
2588
2589 /* Increase if needed */
2590 while (mul-- != 0 && i->prod_level < PRODLEVEL_MAXIMUM) {
2591 i->prod_level = min(i->prod_level * 2, PRODLEVEL_MAXIMUM);
2592 recalculate_multipliers = true;
2593 if (str == STR_NULL) str = indspec->production_up_text;
2594 }
2595
2596 /* Decrease if needed */
2597 while (div-- != 0 && !closeit) {
2598 if (i->prod_level == PRODLEVEL_MINIMUM) {
2599 closeit = true;
2600 } else {
2601 i->prod_level = max(i->prod_level / 2, (int)PRODLEVEL_MINIMUM); // typecast to int required to please MSVC
2602 recalculate_multipliers = true;
2603 if (str == STR_NULL) str = indspec->production_down_text;
2604 }
2605 }
2606
2607 /* Increase or Decreasing the production level if needed */
2608 if (increment != 0) {
2609 if (increment < 0 && i->prod_level == PRODLEVEL_MINIMUM) {
2610 closeit = true;
2611 } else {
2612 i->prod_level = ClampU(i->prod_level + increment, PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
2613 recalculate_multipliers = true;
2614 }
2615 }
2616
2617 /* Recalculate production_rate
2618 * For non-smooth economy these should always be synchronized with prod_level */
2619 if (recalculate_multipliers) i->RecomputeProductionMultipliers();
2620
2621 /* Close if needed and allowed */
2622 if (closeit && !CheckIndustryCloseDownProtection(i->type)) {
2623 i->prod_level = PRODLEVEL_CLOSURE;
2624 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
2625 str = indspec->closure_text;
2626 }
2627
2628 if (!suppress_message && str != STR_NULL) {
2629 NewsType nt;
2630 /* Compute news category */
2631 if (closeit) {
2632 nt = NT_INDUSTRY_CLOSE;
2633 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index));
2634 Game::NewEvent(new ScriptEventIndustryClose(i->index));
2635 } else {
2636 switch (WhoCanServiceIndustry(i)) {
2637 case 0: nt = NT_INDUSTRY_NOBODY; break;
2638 case 1: nt = NT_INDUSTRY_OTHER; break;
2639 case 2: nt = NT_INDUSTRY_COMPANY; break;
2640 default: NOT_REACHED();
2641 }
2642 }
2643 /* Set parameters of news string */
2644 if (str > STR_LAST_STRINGID) {
2645 SetDParam(0, STR_TOWN_NAME);
2646 SetDParam(1, i->town->index);
2647 SetDParam(2, indspec->name);
2648 } else if (closeit) {
2649 SetDParam(0, STR_FORMAT_INDUSTRY_NAME);
2650 SetDParam(1, i->town->index);
2651 SetDParam(2, indspec->name);
2652 } else {
2653 SetDParam(0, i->index);
2654 }
2655 /* and report the news to the user */
2656 if (closeit) {
2657 AddTileNewsItem(str, nt, i->location.tile + TileDiffXY(1, 1));
2658 } else {
2659 AddIndustryNewsItem(str, nt, i->index);
2660 }
2661 }
2662 }
2663
2671 void IndustryDailyLoop()
2672 {
2673 _economy.industry_daily_change_counter += _economy.industry_daily_increment;
2674
2675 /* Bits 16-31 of industry_construction_counter contain the number of industries to change/create today,
2676 * the lower 16 bit are a fractional part that might accumulate over several days until it
2677 * is sufficient for an industry. */
2678 uint16 change_loop = _economy.industry_daily_change_counter >> 16;
2679
2680 /* Reset the active part of the counter, just keeping the "fractional part" */
2681 _economy.industry_daily_change_counter &= 0xFFFF;
2682
2683 if (change_loop == 0) {
2684 return; // Nothing to do? get out
2685 }
2686
2687 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
2688
2689 /* perform the required industry changes for the day */
2690
2691 uint perc = 3; // Between 3% and 9% chance of creating a new industry.
2692 if ((_industry_builder.wanted_inds >> 16) > GetCurrentTotalNumberOfIndustries()) {
2693 perc = min(9u, perc + (_industry_builder.wanted_inds >> 16) - GetCurrentTotalNumberOfIndustries());
2694 }
2695 for (uint16 j = 0; j < change_loop; j++) {
2696 if (Chance16(perc, 100)) {
2697 _industry_builder.TryBuildNewIndustry();
2698 } else {
2699 Industry *i = Industry::GetRandom();
2700 if (i != NULL) {
2701 ChangeIndustryProduction(i, false);
2702 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
2703 }
2704 }
2705 }
2706
2707 cur_company.Restore();
2708
2709 /* production-change */
2710 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 1);
2711 }
2712
2713 void IndustryMonthlyLoop()
2714 {
2715 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
2716
2717 _industry_builder.MonthlyLoop();
2718
2719 Industry *i;
2720 FOR_ALL_INDUSTRIES(i) {
2721 UpdateIndustryStatistics(i);
2722 if (i->prod_level == PRODLEVEL_CLOSURE) {
2723 delete i;
2724 } else {
2725 ChangeIndustryProduction(i, true);
2726 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
2727 }
2728 }
2729
2730 cur_company.Restore();
2731
2732 /* production-change */
2733 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 1);
2734 }
2735
2736
2737 void InitializeIndustries()
2738 {
2739 Industry::ResetIndustryCounts();
2740 _industry_sound_tile = 0;
2741
2742 _industry_builder.Reset();
2743 }
2744
2746 void CheckIndustries()
2747 {
2748 int count = 0;
2749 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2750 if (Industry::GetIndustryTypeCount(it) > 0) continue; // Types of existing industries can be skipped.
2751
2752 bool force_at_least_one;
2753 uint32 chance = GetScaledIndustryGenerationProbability(it, &force_at_least_one);
2754 if (chance == 0 || !force_at_least_one) continue; // Types that are not available can be skipped.
2755
2756 const IndustrySpec *is = GetIndustrySpec(it);
2757 SetDParam(0, is->name);
2758 ShowErrorMessage(STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES, STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION, WL_WARNING);
2759
2760 count++;
2761 if (count >= 3) break; // Don't swamp the user with errors.
2762 }
2763 }
2764
2769 bool IndustrySpec::IsRawIndustry() const
2770 {
2771 return (this->life_type & (INDUSTRYLIFE_EXTRACTIVE | INDUSTRYLIFE_ORGANIC)) != 0;
2772 }
2773
2778 bool IndustrySpec::IsProcessingIndustry() const
2779 {
2780 /* Lumber mills are neither raw nor processing */
2781 return (this->life_type & INDUSTRYLIFE_PROCESSING) != 0 &&
2782 (this->behaviour & INDUSTRYBEH_CUT_TREES) == 0;
2783 }
2784
2789 Money IndustrySpec::GetConstructionCost() const
2790 {
2791 /* Building raw industries like secondary uses different price base */
2792 return (_price[(_settings_game.construction.raw_industry_construction == 1 && this->IsRawIndustry()) ?
2793 PR_BUILD_INDUSTRY_RAW : PR_BUILD_INDUSTRY] * this->cost_multiplier) >> 8;
2794 }
2795
2802 Money IndustrySpec::GetRemovalCost() const
2803 {
2804 return (_price[PR_CLEAR_INDUSTRY] * this->removal_cost_multiplier) >> 8;
2805 }
2806
2811 bool IndustrySpec::UsesSmoothEconomy() const
2812 {
2813 return _settings_game.economy.smooth_economy &&
2814 !(HasBit(this->callback_mask, CBM_IND_PRODUCTION_256_TICKS) || HasBit(this->callback_mask, CBM_IND_PRODUCTION_CARGO_ARRIVAL)) && // production callbacks
2815 !(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
2816 }
2817
2818 static CommandCost TerraformTile_Industry(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
2819 {
2820 if (AutoslopeEnabled()) {
2821 /* We imitate here TTDP's behaviour:
2822 * - Both new and old slope must not be steep.
2823 * - TileMaxZ must not be changed.
2824 * - Allow autoslope by default.
2825 * - Disallow autoslope if callback succeeds and returns non-zero.
2826 */
2827 Slope tileh_old = GetTileSlope(tile);
2828 /* TileMaxZ must not be changed. Slopes must not be steep. */
2829 if (!IsSteepSlope(tileh_old) && !IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) {
2830 const IndustryGfx gfx = GetIndustryGfx(tile);
2831 const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
2832
2833 /* Call callback 3C 'disable autosloping for industry tiles'. */
2834 if (HasBit(itspec->callback_mask, CBM_INDT_AUTOSLOPE)) {
2835 /* If the callback fails, allow autoslope. */
2836 uint16 res = GetIndustryTileCallback(CBID_INDTILE_AUTOSLOPE, 0, 0, gfx, Industry::GetByTile(tile), tile);
2837 if (res == CALLBACK_FAILED || !ConvertBooleanCallback(itspec->grf_prop.grffile, CBID_INDTILE_AUTOSLOPE, res)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
2838 } else {
2839 /* allow autoslope */
2840 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
2841 }
2842 }
2843 }
2844 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
2845 }
2846
2847 extern const TileTypeProcs _tile_type_industry_procs = {
2848 DrawTile_Industry, // draw_tile_proc
2849 GetSlopePixelZ_Industry, // get_slope_z_proc
2850 ClearTile_Industry, // clear_tile_proc
2851 AddAcceptedCargo_Industry, // add_accepted_cargo_proc
2852 GetTileDesc_Industry, // get_tile_desc_proc
2853 GetTileTrackStatus_Industry, // get_tile_track_status_proc
2854 ClickTile_Industry, // click_tile_proc
2855 AnimateTile_Industry, // animate_tile_proc
2856 TileLoop_Industry, // tile_loop_proc
2857 ChangeTileOwner_Industry, // change_tile_owner_proc
2858 NULL, // add_produced_cargo_proc
2859 NULL, // vehicle_enter_tile_proc
2860 GetFoundation_Industry, // get_foundation_proc
2861 TerraformTile_Industry, // terraform_tile_proc
2862 };