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 27932 2017-11-25 16:50:28Z frosch $ */
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
499 static bool TransportIndustryGoods(TileIndex tile)
500 {
501 Industry *i = Industry::GetByTile(tile);
502 const IndustrySpec *indspec = GetIndustrySpec(i->type);
503 bool moved_cargo = false;
504
505 StationFinder stations(i->location);
506
507 for (uint j = 0; j < lengthof(i->produced_cargo_waiting); j++) {
508 uint cw = min(i->produced_cargo_waiting[j], 255);
509 if (cw > indspec->minimal_cargo && i->produced_cargo[j] != CT_INVALID) {
510 i->produced_cargo_waiting[j] -= cw;
511
512 /* fluctuating economy? */
513 if (EconomyIsInRecession()) cw = (cw + 1) / 2;
514
515 i->this_month_production[j] += cw;
516
517 uint am = MoveGoodsToStation(i->produced_cargo[j], cw, ST_INDUSTRY, i->index, stations.GetStations());
518 i->this_month_transported[j] += am;
519
520 moved_cargo |= (am != 0);
521 }
522 }
523
524 return moved_cargo;
525 }
526
527
528 static void AnimateTile_Industry(TileIndex tile)
529 {
530 IndustryGfx gfx = GetIndustryGfx(tile);
531
532 if (GetIndustryTileSpec(gfx)->animation.status != ANIM_STATUS_NO_ANIMATION) {
533 AnimateNewIndustryTile(tile);
534 return;
535 }
536
537 switch (gfx) {
538 case GFX_SUGAR_MINE_SIEVE:
539 if ((_tick_counter & 1) == 0) {
540 byte m = GetAnimationFrame(tile) + 1;
541
542 if (_settings_client.sound.ambient) {
543 switch (m & 7) {
544 case 2: SndPlayTileFx(SND_2D_RIP_2, tile); break;
545 case 6: SndPlayTileFx(SND_29_RIP, tile); break;
546 }
547 }
548
549 if (m >= 96) {
550 m = 0;
551 DeleteAnimatedTile(tile);
552 }
553 SetAnimationFrame(tile, m);
554
555 MarkTileDirtyByTile(tile);
556 }
557 break;
558
559 case GFX_TOFFEE_QUARY:
560 if ((_tick_counter & 3) == 0) {
561 byte m = GetAnimationFrame(tile);
562
563 if (_industry_anim_offs_toffee[m] == 0xFF && _settings_client.sound.ambient) {
564 SndPlayTileFx(SND_30_CARTOON_SOUND, tile);
565 }
566
567 if (++m >= 70) {
568 m = 0;
569 DeleteAnimatedTile(tile);
570 }
571 SetAnimationFrame(tile, m);
572
573 MarkTileDirtyByTile(tile);
574 }
575 break;
576
577 case GFX_BUBBLE_CATCHER:
578 if ((_tick_counter & 1) == 0) {
579 byte m = GetAnimationFrame(tile);
580
581 if (++m >= 40) {
582 m = 0;
583 DeleteAnimatedTile(tile);
584 }
585 SetAnimationFrame(tile, m);
586
587 MarkTileDirtyByTile(tile);
588 }
589 break;
590
591 /* Sparks on a coal plant */
592 case GFX_POWERPLANT_SPARKS:
593 if ((_tick_counter & 3) == 0) {
594 byte m = GetAnimationFrame(tile);
595 if (m == 6) {
596 SetAnimationFrame(tile, 0);
597 DeleteAnimatedTile(tile);
598 } else {
599 SetAnimationFrame(tile, m + 1);
600 MarkTileDirtyByTile(tile);
601 }
602 }
603 break;
604
605 case GFX_TOY_FACTORY:
606 if ((_tick_counter & 1) == 0) {
607 byte m = GetAnimationFrame(tile) + 1;
608
609 switch (m) {
610 case 1: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2C_MACHINERY, tile); break;
611 case 23: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2B_COMEDY_HIT, tile); break;
612 case 28: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2A_EXTRACT_AND_POP, tile); break;
613 default:
614 if (m >= 50) {
615 int n = GetIndustryAnimationLoop(tile) + 1;
616 m = 0;
617 if (n >= 8) {
618 n = 0;
619 DeleteAnimatedTile(tile);
620 }
621 SetIndustryAnimationLoop(tile, n);
622 }
623 }
624
625 SetAnimationFrame(tile, m);
626 MarkTileDirtyByTile(tile);
627 }
628 break;
629
630 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
631 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
632 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
633 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
634 if ((_tick_counter & 3) == 0) {
635 IndustryGfx gfx = GetIndustryGfx(tile);
636
637 gfx = (gfx < 155) ? gfx + 1 : 148;
638 SetIndustryGfx(tile, gfx);
639 MarkTileDirtyByTile(tile);
640 }
641 break;
642
643 case GFX_OILWELL_ANIMATED_1:
644 case GFX_OILWELL_ANIMATED_2:
645 case GFX_OILWELL_ANIMATED_3:
646 if ((_tick_counter & 7) == 0) {
647 bool b = Chance16(1, 7);
648 IndustryGfx gfx = GetIndustryGfx(tile);
649
650 byte m = GetAnimationFrame(tile) + 1;
651 if (m == 4 && (m = 0, ++gfx) == GFX_OILWELL_ANIMATED_3 + 1 && (gfx = GFX_OILWELL_ANIMATED_1, b)) {
652 SetIndustryGfx(tile, GFX_OILWELL_NOT_ANIMATED);
653 SetIndustryConstructionStage(tile, 3);
654 DeleteAnimatedTile(tile);
655 } else {
656 SetAnimationFrame(tile, m);
657 SetIndustryGfx(tile, gfx);
658 MarkTileDirtyByTile(tile);
659 }
660 }
661 break;
662
663 case GFX_COAL_MINE_TOWER_ANIMATED:
664 case GFX_COPPER_MINE_TOWER_ANIMATED:
665 case GFX_GOLD_MINE_TOWER_ANIMATED: {
666 int state = _tick_counter & 0x7FF;
667
668 if ((state -= 0x400) < 0) return;
669
670 if (state < 0x1A0) {
671 if (state < 0x20 || state >= 0x180) {
672 byte m = GetAnimationFrame(tile);
673 if (!(m & 0x40)) {
674 SetAnimationFrame(tile, m | 0x40);
675 if (_settings_client.sound.ambient) SndPlayTileFx(SND_0B_MINING_MACHINERY, tile);
676 }
677 if (state & 7) return;
678 } else {
679 if (state & 3) return;
680 }
681 byte m = (GetAnimationFrame(tile) + 1) | 0x40;
682 if (m > 0xC2) m = 0xC0;
683 SetAnimationFrame(tile, m);
684 MarkTileDirtyByTile(tile);
685 } else if (state >= 0x200 && state < 0x3A0) {
686 int i = (state < 0x220 || state >= 0x380) ? 7 : 3;
687 if (state & i) return;
688
689 byte m = (GetAnimationFrame(tile) & 0xBF) - 1;
690 if (m < 0x80) m = 0x82;
691 SetAnimationFrame(tile, m);
692 MarkTileDirtyByTile(tile);
693 }
694 break;
695 }
696 }
697 }
698
699 static void CreateChimneySmoke(TileIndex tile)
700 {
701 uint x = TileX(tile) * TILE_SIZE;
702 uint y = TileY(tile) * TILE_SIZE;
703 int z = GetTileMaxPixelZ(tile);
704
705 CreateEffectVehicle(x + 15, y + 14, z + 59, EV_CHIMNEY_SMOKE);
706 }
707
708 static void MakeIndustryTileBigger(TileIndex tile)
709 {
710 byte cnt = GetIndustryConstructionCounter(tile) + 1;
711 if (cnt != 4) {
712 SetIndustryConstructionCounter(tile, cnt);
713 return;
714 }
715
716 byte stage = GetIndustryConstructionStage(tile) + 1;
717 SetIndustryConstructionCounter(tile, 0);
718 SetIndustryConstructionStage(tile, stage);
719 StartStopIndustryTileAnimation(tile, IAT_CONSTRUCTION_STATE_CHANGE);
720 if (stage == INDUSTRY_COMPLETED) SetIndustryCompleted(tile);
721
722 MarkTileDirtyByTile(tile);
723
724 if (!IsIndustryCompleted(tile)) return;
725
726 IndustryGfx gfx = GetIndustryGfx(tile);
727 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
728 /* New industries are already animated on construction. */
729 return;
730 }
731
732 switch (gfx) {
733 case GFX_POWERPLANT_CHIMNEY:
734 CreateChimneySmoke(tile);
735 break;
736
737 case GFX_OILRIG_1: {
738 /* Do not require an industry tile to be after the first two GFX_OILRIG_1
739 * tiles (like the default oil rig). Do a proper check to ensure the
740 * tiles belong to the same industry and based on that build the oil rig's
741 * station. */
742 TileIndex other = tile + TileDiffXY(0, 1);
743
744 if (IsTileType(other, MP_INDUSTRY) &&
745 GetIndustryGfx(other) == GFX_OILRIG_1 &&
746 GetIndustryIndex(tile) == GetIndustryIndex(other)) {
747 BuildOilRig(tile);
748 }
749 break;
750 }
751
752 case GFX_TOY_FACTORY:
753 case GFX_BUBBLE_CATCHER:
754 case GFX_TOFFEE_QUARY:
755 SetAnimationFrame(tile, 0);
756 SetIndustryAnimationLoop(tile, 0);
757 break;
758
759 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
760 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
761 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
762 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
763 AddAnimatedTile(tile);
764 break;
765 }
766 }
767
768 static void TileLoopIndustry_BubbleGenerator(TileIndex tile)
769 {
770 static const int8 _bubble_spawn_location[3][4] = {
771 { 11, 0, -4, -14 },
772 { -4, -10, -4, 1 },
773 { 49, 59, 60, 65 },
774 };
775
776 if (_settings_client.sound.ambient) SndPlayTileFx(SND_2E_EXTRACT_AND_POP, tile);
777
778 int dir = Random() & 3;
779
780 EffectVehicle *v = CreateEffectVehicleAbove(
781 TileX(tile) * TILE_SIZE + _bubble_spawn_location[0][dir],
782 TileY(tile) * TILE_SIZE + _bubble_spawn_location[1][dir],
783 _bubble_spawn_location[2][dir],
784 EV_BUBBLE
785 );
786
787 if (v != NULL) v->animation_substate = dir;
788 }
789
790 static void TileLoop_Industry(TileIndex tile)
791 {
792 if (IsTileOnWater(tile)) TileLoop_Water(tile);
793
794 /* Normally this doesn't happen, but if an industry NewGRF is removed
795 * an industry that was previously build on water can now be flooded.
796 * If this happens the tile is no longer an industry tile after
797 * returning from TileLoop_Water. */
798 if (!IsTileType(tile, MP_INDUSTRY)) return;
799
800 TriggerIndustryTile(tile, INDTILE_TRIGGER_TILE_LOOP);
801
802 if (!IsIndustryCompleted(tile)) {
803 MakeIndustryTileBigger(tile);
804 return;
805 }
806
807 if (_game_mode == GM_EDITOR) return;
808
809 if (TransportIndustryGoods(tile) && !StartStopIndustryTileAnimation(Industry::GetByTile(tile), IAT_INDUSTRY_DISTRIBUTES_CARGO)) {
810 uint newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_production;
811
812 if (newgfx != INDUSTRYTILE_NOANIM) {
813 ResetIndustryConstructionStage(tile);
814 SetIndustryCompleted(tile);
815 SetIndustryGfx(tile, newgfx);
816 MarkTileDirtyByTile(tile);
817 return;
818 }
819 }
820
821 if (StartStopIndustryTileAnimation(tile, IAT_TILELOOP)) return;
822
823 IndustryGfx newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_next;
824 if (newgfx != INDUSTRYTILE_NOANIM) {
825 ResetIndustryConstructionStage(tile);
826 SetIndustryGfx(tile, newgfx);
827 MarkTileDirtyByTile(tile);
828 return;
829 }
830
831 IndustryGfx gfx = GetIndustryGfx(tile);
832 switch (gfx) {
833 case GFX_COAL_MINE_TOWER_NOT_ANIMATED:
834 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED:
835 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED:
836 if (!(_tick_counter & 0x400) && Chance16(1, 2)) {
837 switch (gfx) {
838 case GFX_COAL_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COAL_MINE_TOWER_ANIMATED; break;
839 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_ANIMATED; break;
840 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_ANIMATED; break;
841 }
842 SetIndustryGfx(tile, gfx);
843 SetAnimationFrame(tile, 0x80);
844 AddAnimatedTile(tile);
845 }
846 break;
847
848 case GFX_OILWELL_NOT_ANIMATED:
849 if (Chance16(1, 6)) {
850 SetIndustryGfx(tile, GFX_OILWELL_ANIMATED_1);
851 SetAnimationFrame(tile, 0);
852 AddAnimatedTile(tile);
853 }
854 break;
855
856 case GFX_COAL_MINE_TOWER_ANIMATED:
857 case GFX_COPPER_MINE_TOWER_ANIMATED:
858 case GFX_GOLD_MINE_TOWER_ANIMATED:
859 if (!(_tick_counter & 0x400)) {
860 switch (gfx) {
861 case GFX_COAL_MINE_TOWER_ANIMATED: gfx = GFX_COAL_MINE_TOWER_NOT_ANIMATED; break;
862 case GFX_COPPER_MINE_TOWER_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_NOT_ANIMATED; break;
863 case GFX_GOLD_MINE_TOWER_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_NOT_ANIMATED; break;
864 }
865 SetIndustryGfx(tile, gfx);
866 SetIndustryCompleted(tile);
867 SetIndustryConstructionStage(tile, 3);
868 DeleteAnimatedTile(tile);
869 }
870 break;
871
872 case GFX_POWERPLANT_SPARKS:
873 if (Chance16(1, 3)) {
874 if (_settings_client.sound.ambient) SndPlayTileFx(SND_0C_ELECTRIC_SPARK, tile);
875 AddAnimatedTile(tile);
876 }
877 break;
878
879 case GFX_COPPER_MINE_CHIMNEY:
880 CreateEffectVehicleAbove(TileX(tile) * TILE_SIZE + 6, TileY(tile) * TILE_SIZE + 6, 43, EV_COPPER_MINE_SMOKE);
881 break;
882
883
884 case GFX_TOY_FACTORY: {
885 Industry *i = Industry::GetByTile(tile);
886 if (i->was_cargo_delivered) {
887 i->was_cargo_delivered = false;
888 SetIndustryAnimationLoop(tile, 0);
889 AddAnimatedTile(tile);
890 }
891 }
892 break;
893
894 case GFX_BUBBLE_GENERATOR:
895 TileLoopIndustry_BubbleGenerator(tile);
896 break;
897
898 case GFX_TOFFEE_QUARY:
899 AddAnimatedTile(tile);
900 break;
901
902 case GFX_SUGAR_MINE_SIEVE:
903 if (Chance16(1, 3)) AddAnimatedTile(tile);
904 break;
905 }
906 }
907
908 static bool ClickTile_Industry(TileIndex tile)
909 {
910 ShowIndustryViewWindow(GetIndustryIndex(tile));
911 return true;
912 }
913
914 static TrackStatus GetTileTrackStatus_Industry(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
915 {
916 return 0;
917 }
918
919 static void ChangeTileOwner_Industry(TileIndex tile, Owner old_owner, Owner new_owner)
920 {
921 /* If the founder merges, the industry was created by the merged company */
922 Industry *i = Industry::GetByTile(tile);
923 if (i->founder == old_owner) i->founder = (new_owner == INVALID_OWNER) ? OWNER_NONE : new_owner;
924 }
925
931 bool IsTileForestIndustry(TileIndex tile)
932 {
933 /* Check for industry tile */
934 if (!IsTileType(tile, MP_INDUSTRY)) return false;
935
936 const Industry *ind = Industry::GetByTile(tile);
937
938 /* Check for organic industry (i.e. not processing or extractive) */
939 if ((GetIndustrySpec(ind->type)->life_type & INDUSTRYLIFE_ORGANIC) == 0) return false;
940
941 /* Check for wood production */
942 for (uint i = 0; i < lengthof(ind->produced_cargo); i++) {
943 /* The industry produces wood. */
944 if (ind->produced_cargo[i] != CT_INVALID && CargoSpec::Get(ind->produced_cargo[i])->label == 'WOOD') return true;
945 }
946
947 return false;
948 }
949
950 static const byte _plantfarmfield_type[] = {1, 1, 1, 1, 1, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6};
951
959 static bool IsSuitableForFarmField(TileIndex tile, bool allow_fields)
960 {
961 switch (GetTileType(tile)) {
962 case MP_CLEAR: return !IsClearGround(tile, CLEAR_SNOW) && !IsClearGround(tile, CLEAR_DESERT) && (allow_fields || !IsClearGround(tile, CLEAR_FIELDS));
963 case MP_TREES: return GetTreeGround(tile) != TREE_GROUND_SHORE;
964 default: return false;
965 }
966 }
967
975 static void SetupFarmFieldFence(TileIndex tile, int size, byte type, DiagDirection side)
976 {
977 TileIndexDiff diff = (DiagDirToAxis(side) == AXIS_Y ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
978
979 do {
980 tile = TILE_MASK(tile);
981
982 if (IsTileType(tile, MP_CLEAR) && IsClearGround(tile, CLEAR_FIELDS)) {
983 byte or_ = type;
984
985 if (or_ == 1 && Chance16(1, 7)) or_ = 2;
986
987 SetFence(tile, side, or_);
988 }
989
990 tile += diff;
991 } while (--size);
992 }
993
994 static void PlantFarmField(TileIndex tile, IndustryID industry)
995 {
996 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
997 if (GetTileZ(tile) + 2 >= GetSnowLine()) return;
998 }
999
1000 /* determine field size */
1001 uint32 r = (Random() & 0x303) + 0x404;
1002 if (_settings_game.game_creation.landscape == LT_ARCTIC) r += 0x404;
1003 uint size_x = GB(r, 0, 8);
1004 uint size_y = GB(r, 8, 8);
1005
1006 TileArea ta(tile - TileDiffXY(min(TileX(tile), size_x / 2), min(TileY(tile), size_y / 2)), size_x, size_y);
1007 ta.ClampToMap();
1008
1009 if (ta.w == 0 || ta.h == 0) return;
1010
1011 /* check the amount of bad tiles */
1012 int count = 0;
1013 TILE_AREA_LOOP(cur_tile, ta) {
1014 assert(cur_tile < MapSize());
1015 count += IsSuitableForFarmField(cur_tile, false);
1016 }
1017 if (count * 2 < ta.w * ta.h) return;
1018
1019 /* determine type of field */
1020 r = Random();
1021 uint counter = GB(r, 5, 3);
1022 uint field_type = GB(r, 8, 8) * 9 >> 8;
1023
1024 /* make field */
1025 TILE_AREA_LOOP(cur_tile, ta) {
1026 assert(cur_tile < MapSize());
1027 if (IsSuitableForFarmField(cur_tile, true)) {
1028 MakeField(cur_tile, field_type, industry);
1029 SetClearCounter(cur_tile, counter);
1030 MarkTileDirtyByTile(cur_tile);
1031 }
1032 }
1033
1034 int type = 3;
1035 if (_settings_game.game_creation.landscape != LT_ARCTIC && _settings_game.game_creation.landscape != LT_TROPIC) {
1036 type = _plantfarmfield_type[Random() & 0xF];
1037 }
1038
1039 SetupFarmFieldFence(ta.tile, ta.h, type, DIAGDIR_NE);
1040 SetupFarmFieldFence(ta.tile, ta.w, type, DIAGDIR_NW);
1041 SetupFarmFieldFence(ta.tile + TileDiffXY(ta.w - 1, 0), ta.h, type, DIAGDIR_SW);
1042 SetupFarmFieldFence(ta.tile + TileDiffXY(0, ta.h - 1), ta.w, type, DIAGDIR_SE);
1043 }
1044
1045 void PlantRandomFarmField(const Industry *i)
1046 {
1047 int x = i->location.w / 2 + Random() % 31 - 16;
1048 int y = i->location.h / 2 + Random() % 31 - 16;
1049
1050 TileIndex tile = TileAddWrap(i->location.tile, x, y);
1051
1052 if (tile != INVALID_TILE) PlantFarmField(tile, i->index);
1053 }
1054
1061 static bool SearchLumberMillTrees(TileIndex tile, void *user_data)
1062 {
1063 if (IsTileType(tile, MP_TREES) && GetTreeGrowth(tile) > 2) {
1064 /* found a tree */
1065
1066 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
1067
1068 _industry_sound_ctr = 1;
1069 _industry_sound_tile = tile;
1070 if (_settings_client.sound.ambient) SndPlayTileFx(SND_38_CHAINSAW, tile);
1071
1072 DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
1073
1074 cur_company.Restore();
1075 return true;
1076 }
1077 return false;
1078 }
1079
1084 static void ChopLumberMillTrees(Industry *i)
1085 {
1086 /* We only want to cut trees if all tiles are completed. */
1087 TILE_AREA_LOOP(tile_cur, i->location) {
1088 if (i->TileBelongsToIndustry(tile_cur)) {
1089 if (!IsIndustryCompleted(tile_cur)) return;
1090 }
1091 }
1092
1093 TileIndex tile = i->location.tile;
1094 if (CircularTileSearch(&tile, 40, SearchLumberMillTrees, NULL)) { // 40x40 tiles to search.
1095 i->produced_cargo_waiting[0] = min(0xffff, i->produced_cargo_waiting[0] + 45); // Found a tree, add according value to waiting cargo.
1096 }
1097 }
1098
1099 static void ProduceIndustryGoods(Industry *i)
1100 {
1101 const IndustrySpec *indsp = GetIndustrySpec(i->type);
1102
1103 /* play a sound? */
1104 if ((i->counter & 0x3F) == 0) {
1105 uint32 r;
1106 uint num;
1107 if (Chance16R(1, 14, r) && (num = indsp->number_of_sounds) != 0 && _settings_client.sound.ambient) {
1108 SndPlayTileFx(
1109 (SoundFx)(indsp->random_sounds[((r >> 16) * num) >> 16]),
1110 i->location.tile);
1111 }
1112 }
1113
1114 i->counter--;
1115
1116 /* produce some cargo */
1117 if ((i->counter % INDUSTRY_PRODUCE_TICKS) == 0) {
1118 if (HasBit(indsp->callback_mask, CBM_IND_PRODUCTION_256_TICKS)) IndustryProductionCallback(i, 1);
1119
1120 IndustryBehaviour indbehav = indsp->behaviour;
1121 i->produced_cargo_waiting[0] = min(0xffff, i->produced_cargo_waiting[0] + i->production_rate[0]);
1122 i->produced_cargo_waiting[1] = min(0xffff, i->produced_cargo_waiting[1] + i->production_rate[1]);
1123
1124 if ((indbehav & INDUSTRYBEH_PLANT_FIELDS) != 0) {
1125 uint16 cb_res = CALLBACK_FAILED;
1126 if (HasBit(indsp->callback_mask, CBM_IND_SPECIAL_EFFECT)) {
1127 cb_res = GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 0, i, i->type, i->location.tile);
1128 }
1129
1130 bool plant;
1131 if (cb_res != CALLBACK_FAILED) {
1132 plant = ConvertBooleanCallback(indsp->grf_prop.grffile, CBID_INDUSTRY_SPECIAL_EFFECT, cb_res);
1133 } else {
1134 plant = Chance16(1, 8);
1135 }
1136
1137 if (plant) PlantRandomFarmField(i);
1138 }
1139 if ((indbehav & INDUSTRYBEH_CUT_TREES) != 0) {
1140 uint16 cb_res = CALLBACK_FAILED;
1141 if (HasBit(indsp->callback_mask, CBM_IND_SPECIAL_EFFECT)) {
1142 cb_res = GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 1, i, i->type, i->location.tile);
1143 }
1144
1145 bool cut;
1146 if (cb_res != CALLBACK_FAILED) {
1147 cut = ConvertBooleanCallback(indsp->grf_prop.grffile, CBID_INDUSTRY_SPECIAL_EFFECT, cb_res);
1148 } else {
1149 cut = ((i->counter % INDUSTRY_CUT_TREE_TICKS) == 0);
1150 }
1151
1152 if (cut) ChopLumberMillTrees(i);
1153 }
1154
1155 TriggerIndustry(i, INDUSTRY_TRIGGER_INDUSTRY_TICK);
1156 StartStopIndustryTileAnimation(i, IAT_INDUSTRY_TICK);
1157 }
1158 }
1159
1160 void OnTick_Industry()
1161 {
1162 if (_industry_sound_ctr != 0) {
1163 _industry_sound_ctr++;
1164
1165 if (_industry_sound_ctr == 75) {
1166 if (_settings_client.sound.ambient) SndPlayTileFx(SND_37_BALLOON_SQUEAK, _industry_sound_tile);
1167 } else if (_industry_sound_ctr == 160) {
1168 _industry_sound_ctr = 0;
1169 if (_settings_client.sound.ambient) SndPlayTileFx(SND_36_CARTOON_CRASH, _industry_sound_tile);
1170 }
1171 }
1172
1173 if (_game_mode == GM_EDITOR) return;
1174
1175 Industry *i;
1176 FOR_ALL_INDUSTRIES(i) {
1177 ProduceIndustryGoods(i);
1178 }
1179 }
1180
1186 static CommandCost CheckNewIndustry_NULL(TileIndex tile)
1187 {
1188 return CommandCost();
1189 }
1190
1196 static CommandCost CheckNewIndustry_Forest(TileIndex tile)
1197 {
1198 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
1199 if (GetTileZ(tile) < HighestSnowLine() + 2) {
1200 return_cmd_error(STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED);
1201 }
1202 }
1203 return CommandCost();
1204 }
1205
1211 static CommandCost CheckNewIndustry_OilRefinery(TileIndex tile)
1212 {
1213 if (_game_mode == GM_EDITOR) return CommandCost();
1214 if (DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _settings_game.game_creation.oil_refinery_limit) return CommandCost();
1215
1216 return_cmd_error(STR_ERROR_CAN_ONLY_BE_POSITIONED);
1217 }
1218
1219 extern bool _ignore_restrictions;
1220
1226 static CommandCost CheckNewIndustry_OilRig(TileIndex tile)
1227 {
1228 if (_game_mode == GM_EDITOR && _ignore_restrictions) return CommandCost();
1229 if (TileHeight(tile) == 0 &&
1230 DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _settings_game.game_creation.oil_refinery_limit) return CommandCost();
1231
1232 return_cmd_error(STR_ERROR_CAN_ONLY_BE_POSITIONED);
1233 }
1234
1240 static CommandCost CheckNewIndustry_Farm(TileIndex tile)
1241 {
1242 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
1243 if (GetTileZ(tile) + 2 >= HighestSnowLine()) {
1244 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1245 }
1246 }
1247 return CommandCost();
1248 }
1249
1255 static CommandCost CheckNewIndustry_Plantation(TileIndex tile)
1256 {
1257 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
1258 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1259 }
1260 return CommandCost();
1261 }
1262
1268 static CommandCost CheckNewIndustry_Water(TileIndex tile)
1269 {
1270 if (GetTropicZone(tile) != TROPICZONE_DESERT) {
1271 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT);
1272 }
1273 return CommandCost();
1274 }
1275
1281 static CommandCost CheckNewIndustry_Lumbermill(TileIndex tile)
1282 {
1283 if (GetTropicZone(tile) != TROPICZONE_RAINFOREST) {
1284 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST);
1285 }
1286 return CommandCost();
1287 }
1288
1294 static CommandCost CheckNewIndustry_BubbleGen(TileIndex tile)
1295 {
1296 if (GetTileZ(tile) > 4) {
1297 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS);
1298 }
1299 return CommandCost();
1300 }
1301
1307 typedef CommandCost CheckNewIndustryProc(TileIndex tile);
1308
1310 static CheckNewIndustryProc * const _check_new_industry_procs[CHECK_END] = {
1311 CheckNewIndustry_NULL,
1312 CheckNewIndustry_Forest,
1313 CheckNewIndustry_OilRefinery,
1314 CheckNewIndustry_Farm,
1315 CheckNewIndustry_Plantation,
1316 CheckNewIndustry_Water,
1317 CheckNewIndustry_Lumbermill,
1318 CheckNewIndustry_BubbleGen,
1319 CheckNewIndustry_OilRig,
1320 };
1321
1332 static CommandCost FindTownForIndustry(TileIndex tile, int type, Town **t)
1333 {
1334 *t = ClosestTownFromTile(tile, UINT_MAX);
1335
1336 if (_settings_game.economy.multiple_industry_per_town) return CommandCost();
1337
1338 const Industry *i;
1339 FOR_ALL_INDUSTRIES(i) {
1340 if (i->type == (byte)type && i->town == *t) {
1341 *t = NULL;
1342 return_cmd_error(STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN);
1343 }
1344 }
1345
1346 return CommandCost();
1347 }
1348
1349 bool IsSlopeRefused(Slope current, Slope refused)
1350 {
1351 if (IsSteepSlope(current)) return true;
1352 if (current != SLOPE_FLAT) {
1353 if (IsSteepSlope(refused)) return true;
1354
1355 Slope t = ComplementSlope(current);
1356
1357 if ((refused & SLOPE_W) && (t & SLOPE_NW)) return true;
1358 if ((refused & SLOPE_S) && (t & SLOPE_NE)) return true;
1359 if ((refused & SLOPE_E) && (t & SLOPE_SW)) return true;
1360 if ((refused & SLOPE_N) && (t & SLOPE_SE)) return true;
1361 }
1362
1363 return false;
1364 }
1365
1378 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)
1379 {
1380 bool refused_slope = false;
1381 bool custom_shape = false;
1382
1383 do {
1384 IndustryGfx gfx = GetTranslatedIndustryTileID(it->gfx);
1385 TileIndex cur_tile = TileAddWrap(tile, it->ti.x, it->ti.y);
1386
1387 if (!IsValidTile(cur_tile)) {
1388 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1389 }
1390
1391 if (gfx == GFX_WATERTILE_SPECIALCHECK) {
1392 if (!IsWaterTile(cur_tile) ||
1393 !IsTileFlat(cur_tile)) {
1394 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1395 }
1396 } else {
1397 CommandCost ret = EnsureNoVehicleOnGround(cur_tile);
1398 if (ret.Failed()) return ret;
1399 if (IsBridgeAbove(cur_tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1400
1401 const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
1402
1403 IndustryBehaviour ind_behav = GetIndustrySpec(type)->behaviour;
1404
1405 /* Perform land/water check if not disabled */
1406 if (!HasBit(its->slopes_refused, 5) && ((HasTileWaterClass(cur_tile) && IsTileOnWater(cur_tile)) == !(ind_behav & INDUSTRYBEH_BUILT_ONWATER))) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1407
1408 if (HasBit(its->callback_mask, CBM_INDT_SHAPE_CHECK)) {
1409 custom_shape = true;
1410 CommandCost ret = PerformIndustryTileSlopeCheck(tile, cur_tile, its, type, gfx, itspec_index, initial_random_bits, founder, creation_type);
1411 if (ret.Failed()) return ret;
1412 } else {
1413 Slope tileh = GetTileSlope(cur_tile);
1414 refused_slope |= IsSlopeRefused(tileh, its->slopes_refused);
1415 }
1416
1417 if ((ind_behav & (INDUSTRYBEH_ONLY_INTOWN | INDUSTRYBEH_TOWN1200_MORE)) || // Tile must be a house
1418 ((ind_behav & INDUSTRYBEH_ONLY_NEARTOWN) && IsTileType(cur_tile, MP_HOUSE))) { // Tile is allowed to be a house (and it is a house)
1419 if (!IsTileType(cur_tile, MP_HOUSE)) {
1420 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS);
1421 }
1422
1423 /* Clear the tiles as OWNER_TOWN to not affect town rating, and to not clear protected buildings */
1424 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
1425 CommandCost ret = DoCommand(cur_tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR);
1426 cur_company.Restore();
1427
1428 if (ret.Failed()) return ret;
1429 } else {
1430 /* Clear the tiles, but do not affect town ratings */
1431 CommandCost ret = DoCommand(cur_tile, 0, 0, DC_AUTO | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR);
1432
1433 if (ret.Failed()) return ret;
1434 }
1435 }
1436 } while ((++it)->ti.x != -0x80);
1437
1438 if (custom_shape_check != NULL) *custom_shape_check = custom_shape;
1439
1440 /* It is almost impossible to have a fully flat land in TG, so what we
1441 * do is that we check if we can make the land flat later on. See
1442 * CheckIfCanLevelIndustryPlatform(). */
1443 if (!refused_slope || (_settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world && !custom_shape && !_ignore_restrictions)) {
1444 return CommandCost();
1445 }
1446 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1447 }
1448
1456 static CommandCost CheckIfIndustryIsAllowed(TileIndex tile, int type, const Town *t)
1457 {
1458 if ((GetIndustrySpec(type)->behaviour & INDUSTRYBEH_TOWN1200_MORE) && t->cache.population < 1200) {
1459 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200);
1460 }
1461
1462 if ((GetIndustrySpec(type)->behaviour & INDUSTRYBEH_ONLY_NEARTOWN) && DistanceMax(t->xy, tile) > 9) {
1463 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER);
1464 }
1465
1466 return CommandCost();
1467 }
1468
1469 static bool CheckCanTerraformSurroundingTiles(TileIndex tile, uint height, int internal)
1470 {
1471 /* Check if we don't leave the map */
1472 if (TileX(tile) == 0 || TileY(tile) == 0 || GetTileType(tile) == MP_VOID) return false;
1473
1474 TileArea ta(tile - TileDiffXY(1, 1), 2, 2);
1475 TILE_AREA_LOOP(tile_walk, ta) {
1476 uint curh = TileHeight(tile_walk);
1477 /* Is the tile clear? */
1478 if ((GetTileType(tile_walk) != MP_CLEAR) && (GetTileType(tile_walk) != MP_TREES)) return false;
1479
1480 /* Don't allow too big of a change if this is the sub-tile check */
1481 if (internal != 0 && Delta(curh, height) > 1) return false;
1482
1483 /* Different height, so the surrounding tiles of this tile
1484 * has to be correct too (in level, or almost in level)
1485 * else you get a chain-reaction of terraforming. */
1486 if (internal == 0 && curh != height) {
1487 if (TileX(tile_walk) == 0 || TileY(tile_walk) == 0 || !CheckCanTerraformSurroundingTiles(tile_walk + TileDiffXY(-1, -1), height, internal + 1)) {
1488 return false;
1489 }
1490 }
1491 }
1492
1493 return true;
1494 }
1495
1500 static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, DoCommandFlag flags, const IndustryTileTable *it, int type)
1501 {
1502 const int MKEND = -0x80; // used for last element in an IndustryTileTable (see build_industry.h)
1503 int max_x = 0;
1504 int max_y = 0;
1505
1506 /* Finds dimensions of largest variant of this industry */
1507 do {
1508 if (it->gfx == 0xFF) continue; // FF been a marquer for a check on clear water, skip it
1509 if (it->ti.x > max_x) max_x = it->ti.x;
1510 if (it->ti.y > max_y) max_y = it->ti.y;
1511 } while ((++it)->ti.x != MKEND);
1512
1513 /* Remember level height */
1514 uint h = TileHeight(tile);
1515
1516 if (TileX(tile) <= _settings_game.construction.industry_platform + 1U || TileY(tile) <= _settings_game.construction.industry_platform + 1U) return false;
1517 /* Check that all tiles in area and surrounding are clear
1518 * this determines that there are no obstructing items */
1519
1520 TileArea ta(tile + TileDiffXY(-_settings_game.construction.industry_platform, -_settings_game.construction.industry_platform),
1521 max_x + 2 + 2 * _settings_game.construction.industry_platform, max_y + 2 + 2 * _settings_game.construction.industry_platform);
1522
1523 if (TileX(ta.tile) + ta.w >= MapMaxX() || TileY(ta.tile) + ta.h >= MapMaxY()) return false;
1524
1525 /* _current_company is OWNER_NONE for randomly generated industries and in editor, or the company who funded or prospected the industry.
1526 * Perform terraforming as OWNER_TOWN to disable autoslope and town ratings. */
1527 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
1528
1529 TILE_AREA_LOOP(tile_walk, ta) {
1530 uint curh = TileHeight(tile_walk);
1531 if (curh != h) {
1532 /* This tile needs terraforming. Check if we can do that without
1533 * damaging the surroundings too much. */
1534 if (!CheckCanTerraformSurroundingTiles(tile_walk, h, 0)) {
1535 cur_company.Restore();
1536 return false;
1537 }
1538 /* This is not 100% correct check, but the best we can do without modifying the map.
1539 * What is missing, is if the difference in height is more than 1.. */
1540 if (DoCommand(tile_walk, SLOPE_N, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND).Failed()) {
1541 cur_company.Restore();
1542 return false;
1543 }
1544 }
1545 }
1546
1547 if (flags & DC_EXEC) {
1548 /* Terraform the land under the industry */
1549 TILE_AREA_LOOP(tile_walk, ta) {
1550 uint curh = TileHeight(tile_walk);
1551 while (curh != h) {
1552 /* We give the terraforming for free here, because we can't calculate
1553 * exact cost in the test-round, and as we all know, that will cause
1554 * a nice assert if they don't match ;) */
1555 DoCommand(tile_walk, SLOPE_N, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND);
1556 curh += (curh > h) ? -1 : 1;
1557 }
1558 }
1559 }
1560
1561 cur_company.Restore();
1562 return true;
1563 }
1564
1565
1572 static CommandCost CheckIfFarEnoughFromConflictingIndustry(TileIndex tile, int type)
1573 {
1574 const IndustrySpec *indspec = GetIndustrySpec(type);
1575 const Industry *i = NULL;
1576
1577 /* On a large map with many industries, it may be faster to check an area. */
1578 static const int dmax = 14;
1579 if (Industry::GetNumItems() > (size_t) (dmax * dmax * 2)) {
1580 const int tx = TileX(tile);
1581 const int ty = TileY(tile);
1582 TileArea tile_area = TileArea(TileXY(max(0, tx - dmax), max(0, ty - dmax)), TileXY(min(MapMaxX(), tx + dmax), min(MapMaxY(), ty + dmax)));
1583 TILE_AREA_LOOP(atile, tile_area) {
1584 if (GetTileType(atile) == MP_INDUSTRY) {
1585 const Industry *i2 = Industry::GetByTile(atile);
1586 if (i == i2) continue;
1587 i = i2;
1588 if (DistanceMax(tile, i->location.tile) > (uint)dmax) continue;
1589 if (i->type == indspec->conflicting[0] ||
1590 i->type == indspec->conflicting[1] ||
1591 i->type == indspec->conflicting[2]) {
1592 return_cmd_error(STR_ERROR_INDUSTRY_TOO_CLOSE);
1593 }
1594 }
1595 }
1596 return CommandCost();
1597 }
1598
1599 FOR_ALL_INDUSTRIES(i) {
1600 /* Within 14 tiles from another industry is considered close */
1601 if (DistanceMax(tile, i->location.tile) > 14) continue;
1602
1603 /* check if there are any conflicting industry types around */
1604 if (i->type == indspec->conflicting[0] ||
1605 i->type == indspec->conflicting[1] ||
1606 i->type == indspec->conflicting[2]) {
1607 return_cmd_error(STR_ERROR_INDUSTRY_TOO_CLOSE);
1608 }
1609 }
1610 return CommandCost();
1611 }
1612
1617 static void AdvertiseIndustryOpening(const Industry *ind)
1618 {
1619 const IndustrySpec *ind_spc = GetIndustrySpec(ind->type);
1620 SetDParam(0, ind_spc->name);
1621 if (ind_spc->new_industry_text > STR_LAST_STRINGID) {
1622 SetDParam(1, STR_TOWN_NAME);
1623 SetDParam(2, ind->town->index);
1624 } else {
1625 SetDParam(1, ind->town->index);
1626 }
1627 AddIndustryNewsItem(ind_spc->new_industry_text, NT_INDUSTRY_OPEN, ind->index);
1628 AI::BroadcastNewEvent(new ScriptEventIndustryOpen(ind->index));
1629 Game::NewEvent(new ScriptEventIndustryOpen(ind->index));
1630 }
1631
1643 static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, const IndustryTileTable *it, byte layout, Town *t, Owner founder, uint16 initial_random_bits)
1644 {
1645 const IndustrySpec *indspec = GetIndustrySpec(type);
1646
1647 i->location = TileArea(tile, 1, 1);
1648 i->type = type;
1649 Industry::IncIndustryTypeCount(type);
1650
1651 i->produced_cargo[0] = indspec->produced_cargo[0];
1652 i->produced_cargo[1] = indspec->produced_cargo[1];
1653 i->accepts_cargo[0] = indspec->accepts_cargo[0];
1654 i->accepts_cargo[1] = indspec->accepts_cargo[1];
1655 i->accepts_cargo[2] = indspec->accepts_cargo[2];
1656 i->production_rate[0] = indspec->production_rate[0];
1657 i->production_rate[1] = indspec->production_rate[1];
1658
1659 /* don't use smooth economy for industries using production related callbacks */
1660 if (indspec->UsesSmoothEconomy()) {
1661 i->production_rate[0] = min((RandomRange(256) + 128) * i->production_rate[0] >> 8, 255);
1662 i->production_rate[1] = min((RandomRange(256) + 128) * i->production_rate[1] >> 8, 255);
1663 }
1664
1665 i->town = t;
1666 i->owner = OWNER_NONE;
1667
1668 uint16 r = Random();
1669 i->random_colour = GB(r, 0, 4);
1670 i->counter = GB(r, 4, 12);
1671 i->random = initial_random_bits;
1672 i->produced_cargo_waiting[0] = 0;
1673 i->produced_cargo_waiting[1] = 0;
1674 i->incoming_cargo_waiting[0] = 0;
1675 i->incoming_cargo_waiting[1] = 0;
1676 i->incoming_cargo_waiting[2] = 0;
1677 i->this_month_production[0] = 0;
1678 i->this_month_production[1] = 0;
1679 i->this_month_transported[0] = 0;
1680 i->this_month_transported[1] = 0;
1681 i->last_month_pct_transported[0] = 0;
1682 i->last_month_pct_transported[1] = 0;
1683 i->last_month_transported[0] = 0;
1684 i->last_month_transported[1] = 0;
1685 i->was_cargo_delivered = false;
1686 i->last_prod_year = _cur_year;
1687 i->founder = founder;
1688
1689 i->construction_date = _date;
1690 i->construction_type = (_game_mode == GM_EDITOR) ? ICT_SCENARIO_EDITOR :
1691 (_generating_world ? ICT_MAP_GENERATION : ICT_NORMAL_GAMEPLAY);
1692
1693 /* Adding 1 here makes it conform to specs of var44 of varaction2 for industries
1694 * 0 = created prior of newindustries
1695 * else, chosen layout + 1 */
1696 i->selected_layout = layout + 1;
1697
1698 i->prod_level = PRODLEVEL_DEFAULT;
1699
1700 /* Call callbacks after the regular fields got initialised. */
1701
1702 if (HasBit(indspec->callback_mask, CBM_IND_PROD_CHANGE_BUILD)) {
1703 uint16 res = GetIndustryCallback(CBID_INDUSTRY_PROD_CHANGE_BUILD, 0, Random(), i, type, INVALID_TILE);
1704 if (res != CALLBACK_FAILED) {
1705 if (res < PRODLEVEL_MINIMUM || res > PRODLEVEL_MAXIMUM) {
1706 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_PROD_CHANGE_BUILD, res);
1707 } else {
1708 i->prod_level = res;
1709 i->RecomputeProductionMultipliers();
1710 }
1711 }
1712 }
1713
1714 if (_generating_world) {
1715 i->last_month_production[0] = i->production_rate[0] * 8;
1716 i->last_month_production[1] = i->production_rate[1] * 8;
1717 } else {
1718 i->last_month_production[0] = i->last_month_production[1] = 0;
1719 }
1720
1721 if (HasBit(indspec->callback_mask, CBM_IND_DECIDE_COLOUR)) {
1722 uint16 res = GetIndustryCallback(CBID_INDUSTRY_DECIDE_COLOUR, 0, 0, i, type, INVALID_TILE);
1723 if (res != CALLBACK_FAILED) {
1724 if (GB(res, 4, 11) != 0) ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_DECIDE_COLOUR, res);
1725 i->random_colour = GB(res, 0, 4);
1726 }
1727 }
1728
1729 if (HasBit(indspec->callback_mask, CBM_IND_INPUT_CARGO_TYPES)) {
1730 for (uint j = 0; j < lengthof(i->accepts_cargo); j++) i->accepts_cargo[j] = CT_INVALID;
1731 for (uint j = 0; j < lengthof(i->accepts_cargo); j++) {
1732 uint16 res = GetIndustryCallback(CBID_INDUSTRY_INPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE);
1733 if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
1734 if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
1735 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_INPUT_CARGO_TYPES, res);
1736 break;
1737 }
1738 i->accepts_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
1739 }
1740 }
1741
1742 if (HasBit(indspec->callback_mask, CBM_IND_OUTPUT_CARGO_TYPES)) {
1743 for (uint j = 0; j < lengthof(i->produced_cargo); j++) i->produced_cargo[j] = CT_INVALID;
1744 for (uint j = 0; j < lengthof(i->produced_cargo); j++) {
1745 uint16 res = GetIndustryCallback(CBID_INDUSTRY_OUTPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE);
1746 if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
1747 if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
1748 ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_OUTPUT_CARGO_TYPES, res);
1749 break;
1750 }
1751 i->produced_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
1752 }
1753 }
1754
1755 /* Plant the tiles */
1756
1757 do {
1758 TileIndex cur_tile = tile + ToTileIndexDiff(it->ti);
1759
1760 if (it->gfx != GFX_WATERTILE_SPECIALCHECK) {
1761 i->location.Add(cur_tile);
1762
1763 WaterClass wc = (IsWaterTile(cur_tile) ? GetWaterClass(cur_tile) : WATER_CLASS_INVALID);
1764
1765 DoCommand(cur_tile, 0, 0, DC_EXEC | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR);
1766
1767 MakeIndustry(cur_tile, i->index, it->gfx, Random(), wc);
1768
1769 if (_generating_world) {
1770 SetIndustryConstructionCounter(cur_tile, 3);
1771 SetIndustryConstructionStage(cur_tile, 2);
1772 }
1773
1774 /* it->gfx is stored in the map. But the translated ID cur_gfx is the interesting one */
1775 IndustryGfx cur_gfx = GetTranslatedIndustryTileID(it->gfx);
1776 const IndustryTileSpec *its = GetIndustryTileSpec(cur_gfx);
1777 if (its->animation.status != ANIM_STATUS_NO_ANIMATION) AddAnimatedTile(cur_tile);
1778 }
1779 } while ((++it)->ti.x != -0x80);
1780
1781 if (GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_PLANT_ON_BUILT) {
1782 for (uint j = 0; j != 50; j++) PlantRandomFarmField(i);
1783 }
1784 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0);
1785
1786 Station::RecomputeIndustriesNearForAll();
1787 }
1788
1805 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)
1806 {
1807 assert(itspec_index < indspec->num_table);
1808 const IndustryTileTable *it = indspec->table[itspec_index];
1809 bool custom_shape_check = false;
1810
1811 *ip = NULL;
1812
1813 SmallVector<ClearedObjectArea, 1> object_areas(_cleared_object_areas);
1814 CommandCost ret = CheckIfIndustryTilesAreFree(tile, it, itspec_index, type, random_initial_bits, founder, creation_type, &custom_shape_check);
1815 _cleared_object_areas = object_areas;
1816 if (ret.Failed()) return ret;
1817
1818 if (HasBit(GetIndustrySpec(type)->callback_mask, CBM_IND_LOCATION)) {
1819 ret = CheckIfCallBackAllowsCreation(tile, type, itspec_index, random_var8f, random_initial_bits, founder, creation_type);
1820 } else {
1821 ret = _check_new_industry_procs[indspec->check_proc](tile);
1822 }
1823 if (ret.Failed()) return ret;
1824
1825 if (!custom_shape_check && _settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world &&
1826 !_ignore_restrictions && !CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER, it, type)) {
1827 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
1828 }
1829
1830 ret = CheckIfFarEnoughFromConflictingIndustry(tile, type);
1831 if (ret.Failed()) return ret;
1832
1833 Town *t = NULL;
1834 ret = FindTownForIndustry(tile, type, &t);
1835 if (ret.Failed()) return ret;
1836 assert(t != NULL);
1837
1838 ret = CheckIfIndustryIsAllowed(tile, type, t);
1839 if (ret.Failed()) return ret;
1840
1841 if (!Industry::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_INDUSTRIES);
1842
1843 if (flags & DC_EXEC) {
1844 *ip = new Industry(tile);
1845 if (!custom_shape_check) CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER | DC_EXEC, it, type);
1846 DoCreateNewIndustry(*ip, tile, type, it, itspec_index, t, founder, random_initial_bits);
1847 }
1848
1849 return CommandCost();
1850 }
1851
1864 CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
1865 {
1866 IndustryType it = GB(p1, 0, 8);
1867 if (it >= NUM_INDUSTRYTYPES) return CMD_ERROR;
1868
1869 const IndustrySpec *indspec = GetIndustrySpec(it);
1870
1871 /* Check if the to-be built/founded industry is available for this climate. */
1872 if (!indspec->enabled || indspec->num_table == 0) return CMD_ERROR;
1873
1874 /* If the setting for raw-material industries is not on, you cannot build raw-material industries.
1875 * Raw material industries are industries that do not accept cargo (at least for now) */
1876 if (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 0 && indspec->IsRawIndustry()) {
1877 return CMD_ERROR;
1878 }
1879
1880 if (_game_mode != GM_EDITOR && GetIndustryProbabilityCallback(it, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, 1) == 0) {
1881 return CMD_ERROR;
1882 }
1883
1884 Randomizer randomizer;
1885 randomizer.SetSeed(p2);
1886 uint16 random_initial_bits = GB(p2, 0, 16);
1887 uint32 random_var8f = randomizer.Next();
1888 int num_layouts = indspec->num_table;
1889 CommandCost ret = CommandCost(STR_ERROR_SITE_UNSUITABLE);
1890 const bool deity_prospect = _current_company == OWNER_DEITY && !HasBit(p1, 16);
1891
1892 Industry *ind = NULL;
1893 if (deity_prospect || (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 2 && indspec->IsRawIndustry())) {
1894 if (flags & DC_EXEC) {
1895 /* Prospected industries are build as OWNER_TOWN to not e.g. be build on owned land of the founder */
1896 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
1897 /* Prospecting has a chance to fail, however we cannot guarantee that something can
1898 * be built on the map, so the chance gets lower when the map is fuller, but there
1899 * is nothing we can really do about that. */
1900 if (deity_prospect || Random() <= indspec->prospecting_chance) {
1901 for (int i = 0; i < 5000; i++) {
1902 /* We should not have more than one Random() in a function call
1903 * because parameter evaluation order is not guaranteed in the c++ standard
1904 */
1905 tile = RandomTile();
1906 /* Start with a random layout */
1907 int layout = RandomRange(num_layouts);
1908 /* Check now each layout, starting with the random one */
1909 for (int j = 0; j < num_layouts; j++) {
1910 layout = (layout + 1) % num_layouts;
1911 ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, cur_company.GetOriginalValue(), _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_PROSPECTCREATION, &ind);
1912 if (ret.Succeeded()) break;
1913 }
1914 if (ret.Succeeded()) break;
1915 }
1916 }
1917 cur_company.Restore();
1918 }
1919 } else {
1920 int layout = GB(p1, 8, 8);
1921 if (layout >= num_layouts) return CMD_ERROR;
1922
1923 /* Check subsequently each layout, starting with the given layout in p1 */
1924 for (int i = 0; i < num_layouts; i++) {
1925 layout = (layout + 1) % num_layouts;
1926 ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, _current_company, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, &ind);
1927 if (ret.Succeeded()) break;
1928 }
1929
1930 /* If it still failed, there's no suitable layout to build here, return the error */
1931 if (ret.Failed()) return ret;
1932 }
1933
1934 if ((flags & DC_EXEC) && ind != NULL && _game_mode != GM_EDITOR) {
1935 AdvertiseIndustryOpening(ind);
1936 }
1937
1938 return CommandCost(EXPENSES_OTHER, indspec->GetConstructionCost());
1939 }
1940
1941
1949 static Industry *CreateNewIndustry(TileIndex tile, IndustryType type, IndustryAvailabilityCallType creation_type)
1950 {
1951 const IndustrySpec *indspec = GetIndustrySpec(type);
1952
1953 uint32 seed = Random();
1954 uint32 seed2 = Random();
1955 Industry *i = NULL;
1956 CommandCost ret = CreateNewIndustryHelper(tile, type, DC_EXEC, indspec, RandomRange(indspec->num_table), seed, GB(seed2, 0, 16), OWNER_NONE, creation_type, &i);
1957 assert(i != NULL || ret.Failed());
1958 return i;
1959 }
1960
1967 static uint32 GetScaledIndustryGenerationProbability(IndustryType it, bool *force_at_least_one)
1968 {
1969 const IndustrySpec *ind_spc = GetIndustrySpec(it);
1970 uint32 chance = ind_spc->appear_creation[_settings_game.game_creation.landscape] * 16; // * 16 to increase precision
1971 if (!ind_spc->enabled || ind_spc->num_table == 0 ||
1972 (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == ID_FUND_ONLY) ||
1973 (chance = GetIndustryProbabilityCallback(it, IACT_MAPGENERATION, chance)) == 0) {
1974 *force_at_least_one = false;
1975 return 0;
1976 } else {
1977 /* We want industries appearing at coast to appear less often on bigger maps, as length of coast increases slower than map area.
1978 * For simplicity we scale in both cases, though scaling the probabilities of all industries has no effect. */
1979 chance = (ind_spc->check_proc == CHECK_REFINERY || ind_spc->check_proc == CHECK_OIL_RIG) ? ScaleByMapSize1D(chance) : ScaleByMapSize(chance);
1980
1981 *force_at_least_one = (chance > 0) && !(ind_spc->behaviour & INDUSTRYBEH_NOBUILT_MAPCREATION) && (_game_mode != GM_EDITOR);
1982 return chance;
1983 }
1984 }
1985
1992 static uint16 GetIndustryGamePlayProbability(IndustryType it, byte *min_number)
1993 {
1994 if (_settings_game.difficulty.industry_density == ID_FUND_ONLY) {
1995 *min_number = 0;
1996 return 0;
1997 }
1998
1999 const IndustrySpec *ind_spc = GetIndustrySpec(it);
2000 byte chance = ind_spc->appear_ingame[_settings_game.game_creation.landscape];
2001 if (!ind_spc->enabled || ind_spc->num_table == 0 ||
2002 ((ind_spc->behaviour & INDUSTRYBEH_BEFORE_1950) && _cur_year > 1950) ||
2003 ((ind_spc->behaviour & INDUSTRYBEH_AFTER_1960) && _cur_year < 1960) ||
2004 (chance = GetIndustryProbabilityCallback(it, IACT_RANDOMCREATION, chance)) == 0) {
2005 *min_number = 0;
2006 return 0;
2007 }
2008 *min_number = (ind_spc->behaviour & INDUSTRYBEH_CANCLOSE_LASTINSTANCE) ? 1 : 0;
2009 return chance;
2010 }
2011
2016 static uint GetNumberOfIndustries()
2017 {
2018 /* Number of industries on a 256x256 map. */
2019 static const uint16 numof_industry_table[] = {
2020 0, // none
2021 0, // minimal
2022 10, // very low
2023 25, // low
2024 55, // normal
2025 80, // high
2026 };
2027
2028 assert(lengthof(numof_industry_table) == ID_END);
2029 uint difficulty = (_game_mode != GM_EDITOR) ? _settings_game.difficulty.industry_density : (uint)ID_VERY_LOW;
2030 return min(IndustryPool::MAX_SIZE, ScaleByMapSize(numof_industry_table[difficulty]));
2031 }
2032
2041 static Industry *PlaceIndustry(IndustryType type, IndustryAvailabilityCallType creation_type, bool try_hard)
2042 {
2043 uint tries = try_hard ? 10000u : 2000u;
2044 for (; tries > 0; tries--) {
2045 Industry *ind = CreateNewIndustry(RandomTile(), type, creation_type);
2046 if (ind != NULL) return ind;
2047 }
2048 return NULL;
2049 }
2050
2056 static void PlaceInitialIndustry(IndustryType type, bool try_hard)
2057 {
2058 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
2059
2060 IncreaseGeneratingWorldProgress(GWP_INDUSTRY);
2061 PlaceIndustry(type, IACT_MAPGENERATION, try_hard);
2062
2063 cur_company.Restore();
2064 }
2065
2070 static uint GetCurrentTotalNumberOfIndustries()
2071 {
2072 int total = 0;
2073 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) total += Industry::GetIndustryTypeCount(it);
2074 return total;
2075 }
2076
2077
2079 void IndustryTypeBuildData::Reset()
2080 {
2081 this->probability = 0;
2082 this->min_number = 0;
2083 this->target_count = 0;
2084 this->max_wait = 1;
2085 this->wait_count = 0;
2086 }
2087
2089 void IndustryBuildData::Reset()
2090 {
2091 this->wanted_inds = GetCurrentTotalNumberOfIndustries() << 16;
2092
2093 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2094 this->builddata[it].Reset();
2095 }
2096 }
2097
2099 void IndustryBuildData::MonthlyLoop()
2100 {
2101 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.
2102 if (_settings_game.difficulty.industry_density == ID_FUND_ONLY) return; // 'no industries' setting.
2103
2104 /* To prevent running out of unused industries for the player to connect,
2105 * add a fraction of new industries each month, but only if the manager can keep up. */
2106 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).
2107 if (GetCurrentTotalNumberOfIndustries() + max_behind >= (this->wanted_inds >> 16)) {
2108 this->wanted_inds += ScaleByMapSize(NEWINDS_PER_MONTH);
2109 }
2110 }
2111
2116 void GenerateIndustries()
2117 {
2118 if (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == ID_FUND_ONLY) return; // No industries in the game.
2119
2120 uint32 industry_probs[NUM_INDUSTRYTYPES];
2121 bool force_at_least_one[NUM_INDUSTRYTYPES];
2122 uint32 total_prob = 0;
2123 uint num_forced = 0;
2124
2125 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2126 industry_probs[it] = GetScaledIndustryGenerationProbability(it, force_at_least_one + it);
2127 total_prob += industry_probs[it];
2128 if (force_at_least_one[it]) num_forced++;
2129 }
2130
2131 uint total_amount = GetNumberOfIndustries();
2132 if (total_prob == 0 || total_amount < num_forced) {
2133 /* Only place the forced ones */
2134 total_amount = num_forced;
2135 }
2136
2137 SetGeneratingWorldProgress(GWP_INDUSTRY, total_amount);
2138
2139 /* Try to build one industry per type independent of any probabilities */
2140 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2141 if (force_at_least_one[it]) {
2142 assert(total_amount > 0);
2143 total_amount--;
2144 PlaceInitialIndustry(it, true);
2145 }
2146 }
2147
2148 /* Add the remaining industries according to their probabilities */
2149 for (uint i = 0; i < total_amount; i++) {
2150 uint32 r = RandomRange(total_prob);
2151 IndustryType it = 0;
2152 while (r >= industry_probs[it]) {
2153 r -= industry_probs[it];
2154 it++;
2155 assert(it < NUM_INDUSTRYTYPES);
2156 }
2157 assert(industry_probs[it] > 0);
2158 PlaceInitialIndustry(it, false);
2159 }
2160 _industry_builder.Reset();
2161 }
2162
2167 static void UpdateIndustryStatistics(Industry *i)
2168 {
2169 for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
2170 if (i->produced_cargo[j] != CT_INVALID) {
2171 byte pct = 0;
2172 if (i->this_month_production[j] != 0) {
2173 i->last_prod_year = _cur_year;
2174 pct = min(i->this_month_transported[j] * 256 / i->this_month_production[j], 255);
2175 }
2176 i->last_month_pct_transported[j] = pct;
2177
2178 i->last_month_production[j] = i->this_month_production[j];
2179 i->this_month_production[j] = 0;
2180
2181 i->last_month_transported[j] = i->this_month_transported[j];
2182 i->this_month_transported[j] = 0;
2183 }
2184 }
2185 }
2186
2191 void Industry::RecomputeProductionMultipliers()
2192 {
2193 const IndustrySpec *indspec = GetIndustrySpec(this->type);
2194 assert(!indspec->UsesSmoothEconomy());
2195
2196 /* Rates are rounded up, so e.g. oilrig always produces some passengers */
2197 this->production_rate[0] = min(CeilDiv(indspec->production_rate[0] * this->prod_level, PRODLEVEL_DEFAULT), 0xFF);
2198 this->production_rate[1] = min(CeilDiv(indspec->production_rate[1] * this->prod_level, PRODLEVEL_DEFAULT), 0xFF);
2199 }
2200
2201
2207 bool IndustryTypeBuildData::GetIndustryTypeData(IndustryType it)
2208 {
2209 byte min_number;
2210 uint32 probability = GetIndustryGamePlayProbability(it, &min_number);
2211 bool changed = min_number != this->min_number || probability != this->probability;
2212 this->min_number = min_number;
2213 this->probability = probability;
2214 return changed;
2215 }
2216
2218 void IndustryBuildData::SetupTargetCount()
2219 {
2220 bool changed = false;
2221 uint num_planned = 0; // Number of industries planned in the industry build data.
2222 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2223 changed |= this->builddata[it].GetIndustryTypeData(it);
2224 num_planned += this->builddata[it].target_count;
2225 }
2226 uint total_amount = this->wanted_inds >> 16; // Desired total number of industries.
2227 changed |= num_planned != total_amount;
2228 if (!changed) return; // All industries are still the same, no need to re-randomize.
2229
2230 /* Initialize the target counts. */
2231 uint force_build = 0; // Number of industries that should always be available.
2232 uint32 total_prob = 0; // Sum of probabilities.
2233 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2234 IndustryTypeBuildData *ibd = this->builddata + it;
2235 force_build += ibd->min_number;
2236 ibd->target_count = ibd->min_number;
2237 total_prob += ibd->probability;
2238 }
2239
2240 if (total_prob == 0) return; // No buildable industries.
2241
2242 /* Subtract forced industries from the number of industries available for construction. */
2243 total_amount = (total_amount <= force_build) ? 0 : total_amount - force_build;
2244
2245 /* Assign number of industries that should be aimed for, by using the probability as a weight. */
2246 while (total_amount > 0) {
2247 uint32 r = RandomRange(total_prob);
2248 IndustryType it = 0;
2249 while (r >= this->builddata[it].probability) {
2250 r -= this->builddata[it].probability;
2251 it++;
2252 assert(it < NUM_INDUSTRYTYPES);
2253 }
2254 assert(this->builddata[it].probability > 0);
2255 this->builddata[it].target_count++;
2256 total_amount--;
2257 }
2258 }
2259
2263 void IndustryBuildData::TryBuildNewIndustry()
2264 {
2265 this->SetupTargetCount();
2266
2267 int missing = 0; // Number of industries that need to be build.
2268 uint count = 0; // Number of industry types eligible for build.
2269 uint32 total_prob = 0; // Sum of probabilities.
2270 IndustryType forced_build = NUM_INDUSTRYTYPES; // Industry type that should be forcibly build.
2271 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2272 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
2273 missing += difference;
2274 if (this->builddata[it].wait_count > 0) continue; // This type may not be built now.
2275 if (difference > 0) {
2276 if (Industry::GetIndustryTypeCount(it) == 0 && this->builddata[it].min_number > 0) {
2277 /* An industry that should exist at least once, is not available. Force it, trying the most needed one first. */
2278 if (forced_build == NUM_INDUSTRYTYPES ||
2279 difference > this->builddata[forced_build].target_count - Industry::GetIndustryTypeCount(forced_build)) {
2280 forced_build = it;
2281 }
2282 }
2283 total_prob += difference;
2284 count++;
2285 }
2286 }
2287
2288 if (EconomyIsInRecession() || (forced_build == NUM_INDUSTRYTYPES && (missing <= 0 || total_prob == 0))) count = 0; // Skip creation of an industry.
2289
2290 if (count >= 1) {
2291 /* If not forced, pick a weighted random industry to build.
2292 * For the case that count == 1, there is no need to draw a random number. */
2293 IndustryType it;
2294 if (forced_build != NUM_INDUSTRYTYPES) {
2295 it = forced_build;
2296 } else {
2297 /* Non-forced, select an industry type to build (weighted random). */
2298 uint32 r = 0; // Initialized to silence the compiler.
2299 if (count > 1) r = RandomRange(total_prob);
2300 for (it = 0; it < NUM_INDUSTRYTYPES; it++) {
2301 if (this->builddata[it].wait_count > 0) continue; // Type may not be built now.
2302 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
2303 if (difference <= 0) continue; // Too many of this kind.
2304 if (count == 1) break;
2305 if (r < (uint)difference) break;
2306 r -= difference;
2307 }
2308 assert(it < NUM_INDUSTRYTYPES && this->builddata[it].target_count > Industry::GetIndustryTypeCount(it));
2309 }
2310
2311 /* Try to create the industry. */
2312 const Industry *ind = PlaceIndustry(it, IACT_RANDOMCREATION, false);
2313 if (ind == NULL) {
2314 this->builddata[it].wait_count = this->builddata[it].max_wait + 1; // Compensate for decrementing below.
2315 this->builddata[it].max_wait = min(1000, this->builddata[it].max_wait + 2);
2316 } else {
2317 AdvertiseIndustryOpening(ind);
2318 this->builddata[it].max_wait = max(this->builddata[it].max_wait / 2, 1); // Reduce waiting time of the industry type.
2319 }
2320 }
2321
2322 /* Decrement wait counters. */
2323 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2324 if (this->builddata[it].wait_count > 0) this->builddata[it].wait_count--;
2325 }
2326 }
2327
2336 static bool CheckIndustryCloseDownProtection(IndustryType type)
2337 {
2338 const IndustrySpec *indspec = GetIndustrySpec(type);
2339
2340 /* oil wells (or the industries with that flag set) are always allowed to closedown */
2341 if ((indspec->behaviour & INDUSTRYBEH_DONT_INCR_PROD) && _settings_game.game_creation.landscape == LT_TEMPERATE) return false;
2342 return (indspec->behaviour & INDUSTRYBEH_CANCLOSE_LASTINSTANCE) == 0 && Industry::GetIndustryTypeCount(type) <= 1;
2343 }
2344
2354 static void CanCargoServiceIndustry(CargoID cargo, Industry *ind, bool *c_accepts, bool *c_produces)
2355 {
2356 if (cargo == CT_INVALID) return;
2357
2358 /* Check for acceptance of cargo */
2359 for (byte j = 0; j < lengthof(ind->accepts_cargo); j++) {
2360 if (cargo == ind->accepts_cargo[j] && !IndustryTemporarilyRefusesCargo(ind, cargo)) {
2361 *c_accepts = true;
2362 break;
2363 }
2364 }
2365
2366 /* Check for produced cargo */
2367 for (byte j = 0; j < lengthof(ind->produced_cargo); j++) {
2368 if (cargo == ind->produced_cargo[j]) {
2369 *c_produces = true;
2370 break;
2371 }
2372 }
2373 }
2374
2388 static int WhoCanServiceIndustry(Industry *ind)
2389 {
2390 /* Find all stations within reach of the industry */
2391 StationList stations;
2392 FindStationsAroundTiles(ind->location, &stations);
2393
2394 if (stations.Length() == 0) return 0; // No stations found at all => nobody services
2395
2396 const Vehicle *v;
2397 int result = 0;
2398 FOR_ALL_VEHICLES(v) {
2399 /* Is it worthwhile to try this vehicle? */
2400 if (v->owner != _local_company && result != 0) continue;
2401
2402 /* Check whether it accepts the right kind of cargo */
2403 bool c_accepts = false;
2404 bool c_produces = false;
2405 if (v->type == VEH_TRAIN && v->IsFrontEngine()) {
2406 for (const Vehicle *u = v; u != NULL; u = u->Next()) {
2407 CanCargoServiceIndustry(u->cargo_type, ind, &c_accepts, &c_produces);
2408 }
2409 } else if (v->type == VEH_ROAD || v->type == VEH_SHIP || v->type == VEH_AIRCRAFT) {
2410 CanCargoServiceIndustry(v->cargo_type, ind, &c_accepts, &c_produces);
2411 } else {
2412 continue;
2413 }
2414 if (!c_accepts && !c_produces) continue; // Wrong cargo
2415
2416 /* Check orders of the vehicle.
2417 * We cannot check the first of shared orders only, since the first vehicle in such a chain
2418 * may have a different cargo type.
2419 */
2420 const Order *o;
2421 FOR_VEHICLE_ORDERS(v, o) {
2422 if (o->IsType(OT_GOTO_STATION) && !(o->GetUnloadType() & OUFB_TRANSFER)) {
2423 /* Vehicle visits a station to load or unload */
2424 Station *st = Station::Get(o->GetDestination());
2425 assert(st != NULL);
2426
2427 /* Same cargo produced by industry is dropped here => not serviced by vehicle v */
2428 if ((o->GetUnloadType() & OUFB_UNLOAD) && !c_accepts) break;
2429
2430 if (stations.Contains(st)) {
2431 if (v->owner == _local_company) return 2; // Company services industry
2432 result = 1; // Competitor services industry
2433 }
2434 }
2435 }
2436 }
2437 return result;
2438 }
2439
2447 static void ReportNewsProductionChangeIndustry(Industry *ind, CargoID type, int percent)
2448 {
2449 NewsType nt;
2450
2451 switch (WhoCanServiceIndustry(ind)) {
2452 case 0: nt = NT_INDUSTRY_NOBODY; break;
2453 case 1: nt = NT_INDUSTRY_OTHER; break;
2454 case 2: nt = NT_INDUSTRY_COMPANY; break;
2455 default: NOT_REACHED();
2456 }
2457 SetDParam(2, abs(percent));
2458 SetDParam(0, CargoSpec::Get(type)->name);
2459 SetDParam(1, ind->index);
2460 AddIndustryNewsItem(
2461 percent >= 0 ? STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH : STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH,
2462 nt,
2463 ind->index
2464 );
2465 }
2466
2467 static const uint PERCENT_TRANSPORTED_60 = 153;
2468 static const uint PERCENT_TRANSPORTED_80 = 204;
2469
2475 static void ChangeIndustryProduction(Industry *i, bool monthly)
2476 {
2477 StringID str = STR_NULL;
2478 bool closeit = false;
2479 const IndustrySpec *indspec = GetIndustrySpec(i->type);
2480 bool standard = false;
2481 bool suppress_message = false;
2482 bool recalculate_multipliers = false;
2483 /* don't use smooth economy for industries using production related callbacks */
2484 bool smooth_economy = indspec->UsesSmoothEconomy();
2485 byte div = 0;
2486 byte mul = 0;
2487 int8 increment = 0;
2488
2489 bool callback_enabled = HasBit(indspec->callback_mask, monthly ? CBM_IND_MONTHLYPROD_CHANGE : CBM_IND_PRODUCTION_CHANGE);
2490 if (callback_enabled) {
2491 uint16 res = GetIndustryCallback(monthly ? CBID_INDUSTRY_MONTHLYPROD_CHANGE : CBID_INDUSTRY_PRODUCTION_CHANGE, 0, Random(), i, i->type, i->location.tile);
2492 if (res != CALLBACK_FAILED) { // failed callback means "do nothing"
2493 suppress_message = HasBit(res, 7);
2494 /* Get the custom message if any */
2495 if (HasBit(res, 8)) str = MapGRFStringID(indspec->grf_prop.grffile->grfid, GB(GetRegister(0x100), 0, 16));
2496 res = GB(res, 0, 4);
2497 switch (res) {
2498 default: NOT_REACHED();
2499 case 0x0: break; // Do nothing, but show the custom message if any
2500 case 0x1: div = 1; break; // Halve industry production. If production reaches the quarter of the default, the industry is closed instead.
2501 case 0x2: mul = 1; break; // Double industry production if it hasn't reached eight times of the original yet.
2502 case 0x3: closeit = true; break; // The industry announces imminent closure, and is physically removed from the map next month.
2503 case 0x4: standard = true; break; // Do the standard random production change as if this industry was a primary one.
2504 case 0x5: case 0x6: case 0x7: // Divide production by 4, 8, 16
2505 case 0x8: div = res - 0x3; break; // Divide production by 32
2506 case 0x9: case 0xA: case 0xB: // Multiply production by 4, 8, 16
2507 case 0xC: mul = res - 0x7; break; // Multiply production by 32
2508 case 0xD: // decrement production
2509 case 0xE: // increment production
2510 increment = res == 0x0D ? -1 : 1;
2511 break;
2512 case 0xF: // Set production to third byte of register 0x100
2513 i->prod_level = Clamp(GB(GetRegister(0x100), 16, 8), PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
2514 recalculate_multipliers = true;
2515 break;
2516 }
2517 }
2518 } else {
2519 if (monthly != smooth_economy) return;
2520 if (indspec->life_type == INDUSTRYLIFE_BLACK_HOLE) return;
2521 }
2522
2523 if (standard || (!callback_enabled && (indspec->life_type & (INDUSTRYLIFE_ORGANIC | INDUSTRYLIFE_EXTRACTIVE)) != 0)) {
2524 /* decrease or increase */
2525 bool only_decrease = (indspec->behaviour & INDUSTRYBEH_DONT_INCR_PROD) && _settings_game.game_creation.landscape == LT_TEMPERATE;
2526
2527 if (smooth_economy) {
2528 closeit = true;
2529 for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
2530 if (i->produced_cargo[j] == CT_INVALID) continue;
2531 uint32 r = Random();
2532 int old_prod, new_prod, percent;
2533 /* If over 60% is transported, mult is 1, else mult is -1. */
2534 int mult = (i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_60) ? 1 : -1;
2535
2536 new_prod = old_prod = i->production_rate[j];
2537
2538 /* For industries with only_decrease flags (temperate terrain Oil Wells),
2539 * the multiplier will always be -1 so they will only decrease. */
2540 if (only_decrease) {
2541 mult = -1;
2542 /* For normal industries, if over 60% is transported, 33% chance for decrease.
2543 * Bonus for very high station ratings (over 80%): 16% chance for decrease. */
2544 } else if (Chance16I(1, ((i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_80) ? 6 : 3), r)) {
2545 mult *= -1;
2546 }
2547
2548 /* 4.5% chance for 3-23% (or 1 unit for very low productions) production change,
2549 * determined by mult value. If mult = 1 prod. increases, else (-1) it decreases. */
2550 if (Chance16I(1, 22, r >> 16)) {
2551 new_prod += mult * (max(((RandomRange(50) + 10) * old_prod) >> 8, 1U));
2552 }
2553
2554 /* Prevent production to overflow or Oil Rig passengers to be over-"produced" */
2555 new_prod = Clamp(new_prod, 1, 255);
2556
2557 if (((indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0) && j == 1) {
2558 new_prod = Clamp(new_prod, 0, 16);
2559 }
2560
2561 /* Do not stop closing the industry when it has the lowest possible production rate */
2562 if (new_prod == old_prod && old_prod > 1) {
2563 closeit = false;
2564 continue;
2565 }
2566
2567 percent = (old_prod == 0) ? 100 : (new_prod * 100 / old_prod - 100);
2568 i->production_rate[j] = new_prod;
2569
2570 /* Close the industry when it has the lowest possible production rate */
2571 if (new_prod > 1) closeit = false;
2572
2573 if (abs(percent) >= 10) {
2574 ReportNewsProductionChangeIndustry(i, i->produced_cargo[j], percent);
2575 }
2576 }
2577 } else {
2578 if (only_decrease || Chance16(1, 3)) {
2579 /* If more than 60% transported, 66% chance of increase, else 33% chance of increase */
2580 if (!only_decrease && (i->last_month_pct_transported[0] > PERCENT_TRANSPORTED_60) != Chance16(1, 3)) {
2581 mul = 1; // Increase production
2582 } else {
2583 div = 1; // Decrease production
2584 }
2585 }
2586 }
2587 }
2588
2589 if (!callback_enabled && (indspec->life_type & INDUSTRYLIFE_PROCESSING)) {
2590 if ( (byte)(_cur_year - i->last_prod_year) >= 5 && Chance16(1, smooth_economy ? 180 : 2)) {
2591 closeit = true;
2592 }
2593 }
2594
2595 /* Increase if needed */
2596 while (mul-- != 0 && i->prod_level < PRODLEVEL_MAXIMUM) {
2597 i->prod_level = min(i->prod_level * 2, PRODLEVEL_MAXIMUM);
2598 recalculate_multipliers = true;
2599 if (str == STR_NULL) str = indspec->production_up_text;
2600 }
2601
2602 /* Decrease if needed */
2603 while (div-- != 0 && !closeit) {
2604 if (i->prod_level == PRODLEVEL_MINIMUM) {
2605 closeit = true;
2606 } else {
2607 i->prod_level = max(i->prod_level / 2, (int)PRODLEVEL_MINIMUM); // typecast to int required to please MSVC
2608 recalculate_multipliers = true;
2609 if (str == STR_NULL) str = indspec->production_down_text;
2610 }
2611 }
2612
2613 /* Increase or Decreasing the production level if needed */
2614 if (increment != 0) {
2615 if (increment < 0 && i->prod_level == PRODLEVEL_MINIMUM) {
2616 closeit = true;
2617 } else {
2618 i->prod_level = ClampU(i->prod_level + increment, PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
2619 recalculate_multipliers = true;
2620 }
2621 }
2622
2623 /* Recalculate production_rate
2624 * For non-smooth economy these should always be synchronized with prod_level */
2625 if (recalculate_multipliers) i->RecomputeProductionMultipliers();
2626
2627 /* Close if needed and allowed */
2628 if (closeit && !CheckIndustryCloseDownProtection(i->type)) {
2629 i->prod_level = PRODLEVEL_CLOSURE;
2630 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
2631 str = indspec->closure_text;
2632 }
2633
2634 if (!suppress_message && str != STR_NULL) {
2635 NewsType nt;
2636 /* Compute news category */
2637 if (closeit) {
2638 nt = NT_INDUSTRY_CLOSE;
2639 AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index));
2640 Game::NewEvent(new ScriptEventIndustryClose(i->index));
2641 } else {
2642 switch (WhoCanServiceIndustry(i)) {
2643 case 0: nt = NT_INDUSTRY_NOBODY; break;
2644 case 1: nt = NT_INDUSTRY_OTHER; break;
2645 case 2: nt = NT_INDUSTRY_COMPANY; break;
2646 default: NOT_REACHED();
2647 }
2648 }
2649 /* Set parameters of news string */
2650 if (str > STR_LAST_STRINGID) {
2651 SetDParam(0, STR_TOWN_NAME);
2652 SetDParam(1, i->town->index);
2653 SetDParam(2, indspec->name);
2654 } else if (closeit) {
2655 SetDParam(0, STR_FORMAT_INDUSTRY_NAME);
2656 SetDParam(1, i->town->index);
2657 SetDParam(2, indspec->name);
2658 } else {
2659 SetDParam(0, i->index);
2660 }
2661 /* and report the news to the user */
2662 if (closeit) {
2663 AddTileNewsItem(str, nt, i->location.tile + TileDiffXY(1, 1));
2664 } else {
2665 AddIndustryNewsItem(str, nt, i->index);
2666 }
2667 }
2668 }
2669
2677 void IndustryDailyLoop()
2678 {
2679 _economy.industry_daily_change_counter += _economy.industry_daily_increment;
2680
2681 /* Bits 16-31 of industry_construction_counter contain the number of industries to change/create today,
2682 * the lower 16 bit are a fractional part that might accumulate over several days until it
2683 * is sufficient for an industry. */
2684 uint16 change_loop = _economy.industry_daily_change_counter >> 16;
2685
2686 /* Reset the active part of the counter, just keeping the "fractional part" */
2687 _economy.industry_daily_change_counter &= 0xFFFF;
2688
2689 if (change_loop == 0) {
2690 return; // Nothing to do? get out
2691 }
2692
2693 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
2694
2695 /* perform the required industry changes for the day */
2696
2697 uint perc = 3; // Between 3% and 9% chance of creating a new industry.
2698 if ((_industry_builder.wanted_inds >> 16) > GetCurrentTotalNumberOfIndustries()) {
2699 perc = min(9u, perc + (_industry_builder.wanted_inds >> 16) - GetCurrentTotalNumberOfIndustries());
2700 }
2701 for (uint16 j = 0; j < change_loop; j++) {
2702 if (Chance16(perc, 100)) {
2703 _industry_builder.TryBuildNewIndustry();
2704 } else {
2705 Industry *i = Industry::GetRandom();
2706 if (i != NULL) {
2707 ChangeIndustryProduction(i, false);
2708 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
2709 }
2710 }
2711 }
2712
2713 cur_company.Restore();
2714
2715 /* production-change */
2716 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 1);
2717 }
2718
2719 void IndustryMonthlyLoop()
2720 {
2721 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
2722
2723 _industry_builder.MonthlyLoop();
2724
2725 Industry *i;
2726 FOR_ALL_INDUSTRIES(i) {
2727 UpdateIndustryStatistics(i);
2728 if (i->prod_level == PRODLEVEL_CLOSURE) {
2729 delete i;
2730 } else {
2731 ChangeIndustryProduction(i, true);
2732 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
2733 }
2734 }
2735
2736 cur_company.Restore();
2737
2738 /* production-change */
2739 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 1);
2740 }
2741
2742
2743 void InitializeIndustries()
2744 {
2745 Industry::ResetIndustryCounts();
2746 _industry_sound_tile = 0;
2747
2748 _industry_builder.Reset();
2749 }
2750
2752 void CheckIndustries()
2753 {
2754 int count = 0;
2755 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
2756 if (Industry::GetIndustryTypeCount(it) > 0) continue; // Types of existing industries can be skipped.
2757
2758 bool force_at_least_one;
2759 uint32 chance = GetScaledIndustryGenerationProbability(it, &force_at_least_one);
2760 if (chance == 0 || !force_at_least_one) continue; // Types that are not available can be skipped.
2761
2762 const IndustrySpec *is = GetIndustrySpec(it);
2763 SetDParam(0, is->name);
2764 ShowErrorMessage(STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES, STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION, WL_WARNING);
2765
2766 count++;
2767 if (count >= 3) break; // Don't swamp the user with errors.
2768 }
2769 }
2770
2775 bool IndustrySpec::IsRawIndustry() const
2776 {
2777 return (this->life_type & (INDUSTRYLIFE_EXTRACTIVE | INDUSTRYLIFE_ORGANIC)) != 0;
2778 }
2779
2784 bool IndustrySpec::IsProcessingIndustry() const
2785 {
2786 /* Lumber mills are neither raw nor processing */
2787 return (this->life_type & INDUSTRYLIFE_PROCESSING) != 0 &&
2788 (this->behaviour & INDUSTRYBEH_CUT_TREES) == 0;
2789 }
2790
2795 Money IndustrySpec::GetConstructionCost() const
2796 {
2797 /* Building raw industries like secondary uses different price base */
2798 return (_price[(_settings_game.construction.raw_industry_construction == 1 && this->IsRawIndustry()) ?
2799 PR_BUILD_INDUSTRY_RAW : PR_BUILD_INDUSTRY] * this->cost_multiplier) >> 8;
2800 }
2801
2808 Money IndustrySpec::GetRemovalCost() const
2809 {
2810 return (_price[PR_CLEAR_INDUSTRY] * this->removal_cost_multiplier) >> 8;
2811 }
2812
2817 bool IndustrySpec::UsesSmoothEconomy() const
2818 {
2819 return _settings_game.economy.smooth_economy &&
2820 !(HasBit(this->callback_mask, CBM_IND_PRODUCTION_256_TICKS) || HasBit(this->callback_mask, CBM_IND_PRODUCTION_CARGO_ARRIVAL)) && // production callbacks
2821 !(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
2822 }
2823
2824 static CommandCost TerraformTile_Industry(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
2825 {
2826 if (AutoslopeEnabled()) {
2827 /* We imitate here TTDP's behaviour:
2828 * - Both new and old slope must not be steep.
2829 * - TileMaxZ must not be changed.
2830 * - Allow autoslope by default.
2831 * - Disallow autoslope if callback succeeds and returns non-zero.
2832 */
2833 Slope tileh_old = GetTileSlope(tile);
2834 /* TileMaxZ must not be changed. Slopes must not be steep. */
2835 if (!IsSteepSlope(tileh_old) && !IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) {
2836 const IndustryGfx gfx = GetIndustryGfx(tile);
2837 const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
2838
2839 /* Call callback 3C 'disable autosloping for industry tiles'. */
2840 if (HasBit(itspec->callback_mask, CBM_INDT_AUTOSLOPE)) {
2841 /* If the callback fails, allow autoslope. */
2842 uint16 res = GetIndustryTileCallback(CBID_INDTILE_AUTOSLOPE, 0, 0, gfx, Industry::GetByTile(tile), tile);
2843 if (res == CALLBACK_FAILED || !ConvertBooleanCallback(itspec->grf_prop.grffile, CBID_INDTILE_AUTOSLOPE, res)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
2844 } else {
2845 /* allow autoslope */
2846 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
2847 }
2848 }
2849 }
2850 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
2851 }
2852
2853 extern const TileTypeProcs _tile_type_industry_procs = {
2854 DrawTile_Industry, // draw_tile_proc
2855 GetSlopePixelZ_Industry, // get_slope_z_proc
2856 ClearTile_Industry, // clear_tile_proc
2857 AddAcceptedCargo_Industry, // add_accepted_cargo_proc
2858 GetTileDesc_Industry, // get_tile_desc_proc
2859 GetTileTrackStatus_Industry, // get_tile_track_status_proc
2860 ClickTile_Industry, // click_tile_proc
2861 AnimateTile_Industry, // animate_tile_proc
2862 TileLoop_Industry, // tile_loop_proc
2863 ChangeTileOwner_Industry, // change_tile_owner_proc
2864 NULL, // add_produced_cargo_proc
2865 NULL, // vehicle_enter_tile_proc
2866 GetFoundation_Industry, // get_foundation_proc
2867 TerraformTile_Industry, // terraform_tile_proc
2868 };