00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "clear_map.h"
00014 #include "industry.h"
00015 #include "station_base.h"
00016 #include "train.h"
00017 #include "viewport_func.h"
00018 #include "command_func.h"
00019 #include "town.h"
00020 #include "news_func.h"
00021 #include "cheat_type.h"
00022 #include "genworld.h"
00023 #include "tree_map.h"
00024 #include "newgrf_cargo.h"
00025 #include "newgrf_debug.h"
00026 #include "newgrf_industries.h"
00027 #include "newgrf_industrytiles.h"
00028 #include "autoslope.h"
00029 #include "water.h"
00030 #include "strings_func.h"
00031 #include "functions.h"
00032 #include "window_func.h"
00033 #include "date_func.h"
00034 #include "vehicle_func.h"
00035 #include "sound_func.h"
00036 #include "animated_tile_func.h"
00037 #include "effectvehicle_func.h"
00038 #include "effectvehicle_base.h"
00039 #include "ai/ai.hpp"
00040 #include "core/pool_func.hpp"
00041 #include "subsidy_func.h"
00042 #include "core/backup_type.hpp"
00043 #include "object_base.h"
00044
00045 #include "table/strings.h"
00046 #include "table/industry_land.h"
00047 #include "table/build_industry.h"
00048
00049 IndustryPool _industry_pool("Industry");
00050 INSTANTIATE_POOL_METHODS(Industry)
00051
00052 void ShowIndustryViewWindow(int industry);
00053 void BuildOilRig(TileIndex tile);
00054
00055 static byte _industry_sound_ctr;
00056 static TileIndex _industry_sound_tile;
00057
00058 uint16 Industry::counts[NUM_INDUSTRYTYPES];
00059
00060 IndustrySpec _industry_specs[NUM_INDUSTRYTYPES];
00061 IndustryTileSpec _industry_tile_specs[NUM_INDUSTRYTILES];
00062 IndustryBuildData _industry_builder;
00063
00070 void ResetIndustries()
00071 {
00072 memset(&_industry_specs, 0, sizeof(_industry_specs));
00073 memcpy(&_industry_specs, &_origin_industry_specs, sizeof(_origin_industry_specs));
00074
00075
00076 for (IndustryType i = 0; i < NUM_INDUSTRYTYPES; i++) {
00077 _industry_specs[i].enabled = i < NEW_INDUSTRYOFFSET &&
00078 HasBit(_origin_industry_specs[i].climate_availability, _settings_game.game_creation.landscape);
00079 }
00080
00081 memset(&_industry_tile_specs, 0, sizeof(_industry_tile_specs));
00082 memcpy(&_industry_tile_specs, &_origin_industry_tile_specs, sizeof(_origin_industry_tile_specs));
00083
00084
00085 _industile_mngr.ResetOverride();
00086 _industry_mngr.ResetOverride();
00087 }
00088
00097 IndustryType GetIndustryType(TileIndex tile)
00098 {
00099 assert(IsTileType(tile, MP_INDUSTRY));
00100
00101 const Industry *ind = Industry::GetByTile(tile);
00102 assert(ind != NULL);
00103 return ind->type;
00104 }
00105
00114 const IndustrySpec *GetIndustrySpec(IndustryType thistype)
00115 {
00116 assert(thistype < NUM_INDUSTRYTYPES);
00117 return &_industry_specs[thistype];
00118 }
00119
00128 const IndustryTileSpec *GetIndustryTileSpec(IndustryGfx gfx)
00129 {
00130 assert(gfx < INVALID_INDUSTRYTILE);
00131 return &_industry_tile_specs[gfx];
00132 }
00133
00134 Industry::~Industry()
00135 {
00136 if (CleaningPool()) return;
00137
00138
00139
00140
00141 if (this->location.w == 0) return;
00142
00143 TILE_AREA_LOOP(tile_cur, this->location) {
00144 if (IsTileType(tile_cur, MP_INDUSTRY)) {
00145 if (GetIndustryIndex(tile_cur) == this->index) {
00146 DeleteNewGRFInspectWindow(GSF_INDUSTRYTILES, tile_cur);
00147
00148
00149 MakeWaterKeepingClass(tile_cur, OWNER_NONE);
00150 }
00151 } else if (IsTileType(tile_cur, MP_STATION) && IsOilRig(tile_cur)) {
00152 DeleteOilRig(tile_cur);
00153 }
00154 }
00155
00156 if (GetIndustrySpec(this->type)->behaviour & INDUSTRYBEH_PLANT_FIELDS) {
00157 TileArea ta(this->location.tile - TileDiffXY(min(TileX(this->location.tile), 21), min(TileY(this->location.tile), 21)), 42, 42);
00158 ta.ClampToMap();
00159
00160
00161 TILE_AREA_LOOP(tile_cur, ta) {
00162 if (IsTileType(tile_cur, MP_CLEAR) && IsClearGround(tile_cur, CLEAR_FIELDS) &&
00163 GetIndustryIndexOfField(tile_cur) == this->index) {
00164 SetIndustryIndexOfField(tile_cur, INVALID_INDUSTRY);
00165 }
00166 }
00167 }
00168
00169
00170 ReleaseDisastersTargetingIndustry(this->index);
00171
00172 DecIndustryTypeCount(this->type);
00173
00174 DeleteIndustryNews(this->index);
00175 DeleteWindowById(WC_INDUSTRY_VIEW, this->index);
00176 DeleteNewGRFInspectWindow(GSF_INDUSTRIES, this->index);
00177
00178 DeleteSubsidyWith(ST_INDUSTRY, this->index);
00179 CargoPacket::InvalidateAllFrom(ST_INDUSTRY, this->index);
00180 }
00181
00186 void Industry::PostDestructor(size_t index)
00187 {
00188 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0);
00189 Station::RecomputeIndustriesNearForAll();
00190 }
00191
00192
00197 Industry *Industry::GetRandom()
00198 {
00199 if (Industry::GetNumItems() == 0) return NULL;
00200 int num = RandomRange((uint16)Industry::GetNumItems());
00201 size_t index = MAX_UVALUE(size_t);
00202
00203 while (num >= 0) {
00204 num--;
00205 index++;
00206
00207
00208 while (!Industry::IsValidID(index)) {
00209 index++;
00210 assert(index < Industry::GetPoolSize());
00211 }
00212 }
00213
00214 return Industry::Get(index);
00215 }
00216
00217
00218 static void IndustryDrawSugarMine(const TileInfo *ti)
00219 {
00220 if (!IsIndustryCompleted(ti->tile)) return;
00221
00222 const DrawIndustryAnimationStruct *d = &_draw_industry_spec1[GetAnimationFrame(ti->tile)];
00223
00224 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_SIEVE + d->image_1, PAL_NONE, d->x, 0);
00225
00226 if (d->image_2 != 0) {
00227 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_CLOUDS + d->image_2 - 1, PAL_NONE, 8, 41);
00228 }
00229
00230 if (d->image_3 != 0) {
00231 AddChildSpriteScreen(SPR_IT_SUGAR_MINE_PILE + d->image_3 - 1, PAL_NONE,
00232 _drawtile_proc1[d->image_3 - 1].x, _drawtile_proc1[d->image_3 - 1].y);
00233 }
00234 }
00235
00236 static void IndustryDrawToffeeQuarry(const TileInfo *ti)
00237 {
00238 uint8 x = 0;
00239
00240 if (IsIndustryCompleted(ti->tile)) {
00241 x = _industry_anim_offs_toffee[GetAnimationFrame(ti->tile)];
00242 if (x == 0xFF) {
00243 x = 0;
00244 }
00245 }
00246
00247 AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_SHOVEL, PAL_NONE, 22 - x, 24 + x);
00248 AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_TOFFEE, PAL_NONE, 6, 14);
00249 }
00250
00251 static void IndustryDrawBubbleGenerator( const TileInfo *ti)
00252 {
00253 if (IsIndustryCompleted(ti->tile)) {
00254 AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_BUBBLE, PAL_NONE, 5, _industry_anim_offs_bubbles[GetAnimationFrame(ti->tile)]);
00255 } else {
00256 AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_SPRING, PAL_NONE, 3, 67);
00257 }
00258 }
00259
00260 static void IndustryDrawToyFactory(const TileInfo *ti)
00261 {
00262 const DrawIndustryAnimationStruct *d = &_industry_anim_offs_toys[GetAnimationFrame(ti->tile)];
00263
00264 if (d->image_1 != 0xFF) {
00265 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_CLAY, PAL_NONE, d->x, 96 + d->image_1);
00266 }
00267
00268 if (d->image_2 != 0xFF) {
00269 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_ROBOT, PAL_NONE, 16 - d->image_2 * 2, 100 + d->image_2);
00270 }
00271
00272 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP, PAL_NONE, 7, d->image_3);
00273 AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP_HOLDER, PAL_NONE, 0, 42);
00274 }
00275
00276 static void IndustryDrawCoalPlantSparks(const TileInfo *ti)
00277 {
00278 if (IsIndustryCompleted(ti->tile)) {
00279 uint8 image = GetAnimationFrame(ti->tile);
00280
00281 if (image != 0 && image < 7) {
00282 AddChildSpriteScreen(image + SPR_IT_POWER_PLANT_TRANSFORMERS,
00283 PAL_NONE,
00284 _coal_plant_sparks[image - 1].x,
00285 _coal_plant_sparks[image - 1].y
00286 );
00287 }
00288 }
00289 }
00290
00291 typedef void IndustryDrawTileProc(const TileInfo *ti);
00292 static IndustryDrawTileProc * const _industry_draw_tile_procs[5] = {
00293 IndustryDrawSugarMine,
00294 IndustryDrawToffeeQuarry,
00295 IndustryDrawBubbleGenerator,
00296 IndustryDrawToyFactory,
00297 IndustryDrawCoalPlantSparks,
00298 };
00299
00300 static void DrawTile_Industry(TileInfo *ti)
00301 {
00302 IndustryGfx gfx = GetIndustryGfx(ti->tile);
00303 Industry *ind = Industry::GetByTile(ti->tile);
00304 const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
00305
00306
00307 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
00308
00309
00310
00311
00312 if (indts->grf_prop.spritegroup[0] != NULL && DrawNewIndustryTile(ti, ind, gfx, indts)) {
00313 return;
00314 } else {
00315
00316
00317 if (indts->grf_prop.subst_id != INVALID_INDUSTRYTILE) {
00318 gfx = indts->grf_prop.subst_id;
00319
00320 indts = GetIndustryTileSpec(gfx);
00321 }
00322 }
00323 }
00324
00325 const DrawBuildingsTileStruct *dits = &_industry_draw_tile_data[gfx << 2 | (indts->anim_state ?
00326 GetAnimationFrame(ti->tile) & INDUSTRY_COMPLETED :
00327 GetIndustryConstructionStage(ti->tile))];
00328
00329 SpriteID image = dits->ground.sprite;
00330
00331
00332 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
00333
00334
00335
00336 if (image == SPR_FLAT_WATER_TILE && IsTileOnWater(ti->tile)) {
00337 DrawWaterClassGround(ti);
00338 } else {
00339 DrawGroundSprite(image, GroundSpritePaletteTransform(image, dits->ground.pal, GENERAL_SPRITE_COLOUR(ind->random_colour)));
00340 }
00341
00342
00343 if (IsInvisibilitySet(TO_INDUSTRIES)) return;
00344
00345
00346 image = dits->building.sprite;
00347 if (image != 0) {
00348 AddSortableSpriteToDraw(image, SpriteLayoutPaletteTransform(image, dits->building.pal, GENERAL_SPRITE_COLOUR(ind->random_colour)),
00349 ti->x + dits->subtile_x,
00350 ti->y + dits->subtile_y,
00351 dits->width,
00352 dits->height,
00353 dits->dz,
00354 ti->z,
00355 IsTransparencySet(TO_INDUSTRIES));
00356
00357 if (IsTransparencySet(TO_INDUSTRIES)) return;
00358 }
00359
00360 {
00361 int proc = dits->draw_proc - 1;
00362 if (proc >= 0) _industry_draw_tile_procs[proc](ti);
00363 }
00364 }
00365
00366 static uint GetSlopeZ_Industry(TileIndex tile, uint x, uint y)
00367 {
00368 return GetTileMaxZ(tile);
00369 }
00370
00371 static Foundation GetFoundation_Industry(TileIndex tile, Slope tileh)
00372 {
00373 IndustryGfx gfx = GetIndustryGfx(tile);
00374
00375
00376
00377
00378
00379 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
00380 const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
00381 if (indts->grf_prop.spritegroup[0] != NULL && HasBit(indts->callback_mask, CBM_INDT_DRAW_FOUNDATIONS)) {
00382 uint32 callback_res = GetIndustryTileCallback(CBID_INDTILE_DRAW_FOUNDATIONS, 0, 0, gfx, Industry::GetByTile(tile), tile);
00383 if (callback_res == 0) return FOUNDATION_NONE;
00384 }
00385 }
00386 return FlatteningFoundation(tileh);
00387 }
00388
00389 static void AddAcceptedCargo_Industry(TileIndex tile, CargoArray &acceptance, uint32 *always_accepted)
00390 {
00391 IndustryGfx gfx = GetIndustryGfx(tile);
00392 const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
00393
00394
00395 CargoID raw_accepts_cargo[lengthof(itspec->accepts_cargo)];
00396 uint8 raw_cargo_acceptance[lengthof(itspec->acceptance)];
00397
00398
00399 const CargoID *accepts_cargo = itspec->accepts_cargo;
00400 const uint8 *cargo_acceptance = itspec->acceptance;
00401
00402 if (HasBit(itspec->callback_mask, CBM_INDT_ACCEPT_CARGO)) {
00403 uint16 res = GetIndustryTileCallback(CBID_INDTILE_ACCEPT_CARGO, 0, 0, gfx, Industry::GetByTile(tile), tile);
00404 if (res != CALLBACK_FAILED) {
00405 accepts_cargo = raw_accepts_cargo;
00406 for (uint i = 0; i < lengthof(itspec->accepts_cargo); i++) raw_accepts_cargo[i] = GetCargoTranslation(GB(res, i * 5, 5), itspec->grf_prop.grffile);
00407 }
00408 }
00409
00410 if (HasBit(itspec->callback_mask, CBM_INDT_CARGO_ACCEPTANCE)) {
00411 uint16 res = GetIndustryTileCallback(CBID_INDTILE_CARGO_ACCEPTANCE, 0, 0, gfx, Industry::GetByTile(tile), tile);
00412 if (res != CALLBACK_FAILED) {
00413 cargo_acceptance = raw_cargo_acceptance;
00414 for (uint i = 0; i < lengthof(itspec->accepts_cargo); i++) raw_cargo_acceptance[i] = GB(res, i * 4, 4);
00415 }
00416 }
00417
00418 const Industry *ind = Industry::GetByTile(tile);
00419 for (byte i = 0; i < lengthof(itspec->accepts_cargo); i++) {
00420 CargoID a = accepts_cargo[i];
00421 if (a == CT_INVALID || cargo_acceptance[i] == 0) continue;
00422
00423
00424 acceptance[a] += cargo_acceptance[i];
00425
00426
00427 if (HasBit(*always_accepted, a)) continue;
00428
00429 bool accepts = false;
00430 for (uint cargo_index = 0; cargo_index < lengthof(ind->accepts_cargo); cargo_index++) {
00431
00432 if (ind->accepts_cargo[cargo_index] == a) {
00433 accepts = true;
00434 break;
00435 }
00436 }
00437
00438 if (accepts) continue;
00439
00440
00441 SetBit(*always_accepted, a);
00442 }
00443 }
00444
00445 static void GetTileDesc_Industry(TileIndex tile, TileDesc *td)
00446 {
00447 const Industry *i = Industry::GetByTile(tile);
00448 const IndustrySpec *is = GetIndustrySpec(i->type);
00449
00450 td->owner[0] = i->owner;
00451 td->str = is->name;
00452 if (!IsIndustryCompleted(tile)) {
00453 SetDParamX(td->dparam, 0, td->str);
00454 td->str = STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION;
00455 }
00456
00457 if (is->grf_prop.grffile != NULL) {
00458 td->grf = GetGRFConfig(is->grf_prop.grffile->grfid)->GetName();
00459 }
00460 }
00461
00462 static CommandCost ClearTile_Industry(TileIndex tile, DoCommandFlag flags)
00463 {
00464 Industry *i = Industry::GetByTile(tile);
00465 const IndustrySpec *indspec = GetIndustrySpec(i->type);
00466
00467
00468
00469
00470
00471
00472 if ((_current_company != OWNER_WATER && _game_mode != GM_EDITOR &&
00473 !_cheats.magic_bulldozer.value) ||
00474 ((flags & DC_AUTO) != 0) ||
00475 (_current_company == OWNER_WATER &&
00476 ((indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) ||
00477 HasBit(GetIndustryTileSpec(GetIndustryGfx(tile))->slopes_refused, 5)))) {
00478 SetDParam(1, indspec->name);
00479 return_cmd_error(flags & DC_AUTO ? STR_ERROR_GENERIC_OBJECT_IN_THE_WAY : INVALID_STRING_ID);
00480 }
00481
00482 if (flags & DC_EXEC) {
00483 AI::BroadcastNewEvent(new AIEventIndustryClose(i->index));
00484 delete i;
00485 }
00486 return CommandCost(EXPENSES_CONSTRUCTION, indspec->GetRemovalCost());
00487 }
00488
00489 static void TransportIndustryGoods(TileIndex tile)
00490 {
00491 Industry *i = Industry::GetByTile(tile);
00492 const IndustrySpec *indspec = GetIndustrySpec(i->type);
00493 bool moved_cargo = false;
00494
00495 StationFinder stations(i->location);
00496
00497 for (uint j = 0; j < lengthof(i->produced_cargo_waiting); j++) {
00498 uint cw = min(i->produced_cargo_waiting[j], 255);
00499 if (cw > indspec->minimal_cargo && i->produced_cargo[j] != CT_INVALID) {
00500 i->produced_cargo_waiting[j] -= cw;
00501
00502
00503 if (EconomyIsInRecession()) cw = (cw + 1) / 2;
00504
00505 i->this_month_production[j] += cw;
00506
00507 uint am = MoveGoodsToStation(i->produced_cargo[j], cw, ST_INDUSTRY, i->index, stations.GetStations());
00508 i->this_month_transported[j] += am;
00509
00510 moved_cargo |= (am != 0);
00511 }
00512 }
00513
00514 if (moved_cargo && !StartStopIndustryTileAnimation(i, IAT_INDUSTRY_DISTRIBUTES_CARGO)) {
00515 uint newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_production;
00516
00517 if (newgfx != INDUSTRYTILE_NOANIM) {
00518 ResetIndustryConstructionStage(tile);
00519 SetIndustryCompleted(tile, true);
00520 SetIndustryGfx(tile, newgfx);
00521 MarkTileDirtyByTile(tile);
00522 }
00523 }
00524 }
00525
00526
00527 static void AnimateTile_Industry(TileIndex tile)
00528 {
00529 IndustryGfx gfx = GetIndustryGfx(tile);
00530
00531 if (GetIndustryTileSpec(gfx)->animation.status != ANIM_STATUS_NO_ANIMATION) {
00532 AnimateNewIndustryTile(tile);
00533 return;
00534 }
00535
00536 switch (gfx) {
00537 case GFX_SUGAR_MINE_SIEVE:
00538 if ((_tick_counter & 1) == 0) {
00539 byte m = GetAnimationFrame(tile) + 1;
00540
00541 switch (m & 7) {
00542 case 2: SndPlayTileFx(SND_2D_RIP_2, tile); break;
00543 case 6: SndPlayTileFx(SND_29_RIP, tile); break;
00544 }
00545
00546 if (m >= 96) {
00547 m = 0;
00548 DeleteAnimatedTile(tile);
00549 }
00550 SetAnimationFrame(tile, m);
00551
00552 MarkTileDirtyByTile(tile);
00553 }
00554 break;
00555
00556 case GFX_TOFFEE_QUARY:
00557 if ((_tick_counter & 3) == 0) {
00558 byte m = GetAnimationFrame(tile);
00559
00560 if (_industry_anim_offs_toffee[m] == 0xFF) {
00561 SndPlayTileFx(SND_30_CARTOON_SOUND, tile);
00562 }
00563
00564 if (++m >= 70) {
00565 m = 0;
00566 DeleteAnimatedTile(tile);
00567 }
00568 SetAnimationFrame(tile, m);
00569
00570 MarkTileDirtyByTile(tile);
00571 }
00572 break;
00573
00574 case GFX_BUBBLE_CATCHER:
00575 if ((_tick_counter & 1) == 0) {
00576 byte m = GetAnimationFrame(tile);
00577
00578 if (++m >= 40) {
00579 m = 0;
00580 DeleteAnimatedTile(tile);
00581 }
00582 SetAnimationFrame(tile, m);
00583
00584 MarkTileDirtyByTile(tile);
00585 }
00586 break;
00587
00588
00589 case GFX_POWERPLANT_SPARKS:
00590 if ((_tick_counter & 3) == 0) {
00591 byte m = GetAnimationFrame(tile);
00592 if (m == 6) {
00593 SetAnimationFrame(tile, 0);
00594 DeleteAnimatedTile(tile);
00595 } else {
00596 SetAnimationFrame(tile, m + 1);
00597 MarkTileDirtyByTile(tile);
00598 }
00599 }
00600 break;
00601
00602 case GFX_TOY_FACTORY:
00603 if ((_tick_counter & 1) == 0) {
00604 byte m = GetAnimationFrame(tile) + 1;
00605
00606 switch (m) {
00607 case 1: SndPlayTileFx(SND_2C_MACHINERY, tile); break;
00608 case 23: SndPlayTileFx(SND_2B_COMEDY_HIT, tile); break;
00609 case 28: SndPlayTileFx(SND_2A_EXTRACT_AND_POP, tile); break;
00610 default:
00611 if (m >= 50) {
00612 int n = GetIndustryAnimationLoop(tile) + 1;
00613 m = 0;
00614 if (n >= 8) {
00615 n = 0;
00616 DeleteAnimatedTile(tile);
00617 }
00618 SetIndustryAnimationLoop(tile, n);
00619 }
00620 }
00621
00622 SetAnimationFrame(tile, m);
00623 MarkTileDirtyByTile(tile);
00624 }
00625 break;
00626
00627 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
00628 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
00629 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
00630 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
00631 if ((_tick_counter & 3) == 0) {
00632 IndustryGfx gfx = GetIndustryGfx(tile);
00633
00634 gfx = (gfx < 155) ? gfx + 1 : 148;
00635 SetIndustryGfx(tile, gfx);
00636 MarkTileDirtyByTile(tile);
00637 }
00638 break;
00639
00640 case GFX_OILWELL_ANIMATED_1:
00641 case GFX_OILWELL_ANIMATED_2:
00642 case GFX_OILWELL_ANIMATED_3:
00643 if ((_tick_counter & 7) == 0) {
00644 bool b = Chance16(1, 7);
00645 IndustryGfx gfx = GetIndustryGfx(tile);
00646
00647 byte m = GetAnimationFrame(tile) + 1;
00648 if (m == 4 && (m = 0, ++gfx) == GFX_OILWELL_ANIMATED_3 + 1 && (gfx = GFX_OILWELL_ANIMATED_1, b)) {
00649 SetIndustryGfx(tile, GFX_OILWELL_NOT_ANIMATED);
00650 SetIndustryConstructionStage(tile, 3);
00651 DeleteAnimatedTile(tile);
00652 } else {
00653 SetAnimationFrame(tile, m);
00654 SetIndustryGfx(tile, gfx);
00655 MarkTileDirtyByTile(tile);
00656 }
00657 }
00658 break;
00659
00660 case GFX_COAL_MINE_TOWER_ANIMATED:
00661 case GFX_COPPER_MINE_TOWER_ANIMATED:
00662 case GFX_GOLD_MINE_TOWER_ANIMATED: {
00663 int state = _tick_counter & 0x7FF;
00664
00665 if ((state -= 0x400) < 0) return;
00666
00667 if (state < 0x1A0) {
00668 if (state < 0x20 || state >= 0x180) {
00669 byte m = GetAnimationFrame(tile);
00670 if (!(m & 0x40)) {
00671 SetAnimationFrame(tile, m | 0x40);
00672 SndPlayTileFx(SND_0B_MINING_MACHINERY, tile);
00673 }
00674 if (state & 7) return;
00675 } else {
00676 if (state & 3) return;
00677 }
00678 byte m = (GetAnimationFrame(tile) + 1) | 0x40;
00679 if (m > 0xC2) m = 0xC0;
00680 SetAnimationFrame(tile, m);
00681 MarkTileDirtyByTile(tile);
00682 } else if (state >= 0x200 && state < 0x3A0) {
00683 int i = (state < 0x220 || state >= 0x380) ? 7 : 3;
00684 if (state & i) return;
00685
00686 byte m = (GetAnimationFrame(tile) & 0xBF) - 1;
00687 if (m < 0x80) m = 0x82;
00688 SetAnimationFrame(tile, m);
00689 MarkTileDirtyByTile(tile);
00690 }
00691 break;
00692 }
00693 }
00694 }
00695
00696 static void CreateChimneySmoke(TileIndex tile)
00697 {
00698 uint x = TileX(tile) * TILE_SIZE;
00699 uint y = TileY(tile) * TILE_SIZE;
00700 uint z = GetTileMaxZ(tile);
00701
00702 CreateEffectVehicle(x + 15, y + 14, z + 59, EV_CHIMNEY_SMOKE);
00703 }
00704
00705 static void MakeIndustryTileBigger(TileIndex tile)
00706 {
00707 byte cnt = GetIndustryConstructionCounter(tile) + 1;
00708 if (cnt != 4) {
00709 SetIndustryConstructionCounter(tile, cnt);
00710 return;
00711 }
00712
00713 byte stage = GetIndustryConstructionStage(tile) + 1;
00714 SetIndustryConstructionCounter(tile, 0);
00715 SetIndustryConstructionStage(tile, stage);
00716 StartStopIndustryTileAnimation(tile, IAT_CONSTRUCTION_STATE_CHANGE);
00717 if (stage == INDUSTRY_COMPLETED) SetIndustryCompleted(tile, true);
00718
00719 MarkTileDirtyByTile(tile);
00720
00721 if (!IsIndustryCompleted(tile)) return;
00722
00723 IndustryGfx gfx = GetIndustryGfx(tile);
00724 if (gfx >= NEW_INDUSTRYTILEOFFSET) {
00725
00726 return;
00727 }
00728
00729 switch (gfx) {
00730 case GFX_POWERPLANT_CHIMNEY:
00731 CreateChimneySmoke(tile);
00732 break;
00733
00734 case GFX_OILRIG_1: {
00735
00736
00737
00738
00739 TileIndex other = tile + TileDiffXY(0, 1);
00740
00741 if (IsTileType(other, MP_INDUSTRY) &&
00742 GetIndustryGfx(other) == GFX_OILRIG_1 &&
00743 GetIndustryIndex(tile) == GetIndustryIndex(other)) {
00744 BuildOilRig(tile);
00745 }
00746 break;
00747 }
00748
00749 case GFX_TOY_FACTORY:
00750 case GFX_BUBBLE_CATCHER:
00751 case GFX_TOFFEE_QUARY:
00752 SetAnimationFrame(tile, 0);
00753 SetIndustryAnimationLoop(tile, 0);
00754 break;
00755
00756 case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
00757 case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
00758 case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
00759 case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
00760 AddAnimatedTile(tile);
00761 break;
00762 }
00763 }
00764
00765 static void TileLoopIndustry_BubbleGenerator(TileIndex tile)
00766 {
00767 static const int8 _bubble_spawn_location[3][4] = {
00768 { 11, 0, -4, -14 },
00769 { -4, -10, -4, 1 },
00770 { 49, 59, 60, 65 },
00771 };
00772
00773 SndPlayTileFx(SND_2E_EXTRACT_AND_POP, tile);
00774
00775 int dir = Random() & 3;
00776
00777 EffectVehicle *v = CreateEffectVehicleAbove(
00778 TileX(tile) * TILE_SIZE + _bubble_spawn_location[0][dir],
00779 TileY(tile) * TILE_SIZE + _bubble_spawn_location[1][dir],
00780 _bubble_spawn_location[2][dir],
00781 EV_BUBBLE
00782 );
00783
00784 if (v != NULL) v->animation_substate = dir;
00785 }
00786
00787 static void TileLoop_Industry(TileIndex tile)
00788 {
00789 if (IsTileOnWater(tile)) TileLoop_Water(tile);
00790
00791
00792
00793
00794
00795 if (!IsTileType(tile, MP_INDUSTRY)) return;
00796
00797 TriggerIndustryTile(tile, INDTILE_TRIGGER_TILE_LOOP);
00798
00799 if (!IsIndustryCompleted(tile)) {
00800 MakeIndustryTileBigger(tile);
00801 return;
00802 }
00803
00804 if (_game_mode == GM_EDITOR) return;
00805
00806 TransportIndustryGoods(tile);
00807
00808 if (StartStopIndustryTileAnimation(tile, IAT_TILELOOP)) return;
00809
00810 IndustryGfx newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_next;
00811 if (newgfx != INDUSTRYTILE_NOANIM) {
00812 ResetIndustryConstructionStage(tile);
00813 SetIndustryGfx(tile, newgfx);
00814 MarkTileDirtyByTile(tile);
00815 return;
00816 }
00817
00818 IndustryGfx gfx = GetIndustryGfx(tile);
00819 switch (gfx) {
00820 case GFX_COAL_MINE_TOWER_NOT_ANIMATED:
00821 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED:
00822 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED:
00823 if (!(_tick_counter & 0x400) && Chance16(1, 2)) {
00824 switch (gfx) {
00825 case GFX_COAL_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COAL_MINE_TOWER_ANIMATED; break;
00826 case GFX_COPPER_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_ANIMATED; break;
00827 case GFX_GOLD_MINE_TOWER_NOT_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_ANIMATED; break;
00828 }
00829 SetIndustryGfx(tile, gfx);
00830 SetAnimationFrame(tile, 0x80);
00831 AddAnimatedTile(tile);
00832 }
00833 break;
00834
00835 case GFX_OILWELL_NOT_ANIMATED:
00836 if (Chance16(1, 6)) {
00837 SetIndustryGfx(tile, GFX_OILWELL_ANIMATED_1);
00838 SetAnimationFrame(tile, 0);
00839 AddAnimatedTile(tile);
00840 }
00841 break;
00842
00843 case GFX_COAL_MINE_TOWER_ANIMATED:
00844 case GFX_COPPER_MINE_TOWER_ANIMATED:
00845 case GFX_GOLD_MINE_TOWER_ANIMATED:
00846 if (!(_tick_counter & 0x400)) {
00847 switch (gfx) {
00848 case GFX_COAL_MINE_TOWER_ANIMATED: gfx = GFX_COAL_MINE_TOWER_NOT_ANIMATED; break;
00849 case GFX_COPPER_MINE_TOWER_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_NOT_ANIMATED; break;
00850 case GFX_GOLD_MINE_TOWER_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_NOT_ANIMATED; break;
00851 }
00852 SetIndustryGfx(tile, gfx);
00853 SetIndustryCompleted(tile, true);
00854 SetIndustryConstructionStage(tile, 3);
00855 DeleteAnimatedTile(tile);
00856 }
00857 break;
00858
00859 case GFX_POWERPLANT_SPARKS:
00860 if (Chance16(1, 3)) {
00861 SndPlayTileFx(SND_0C_ELECTRIC_SPARK, tile);
00862 AddAnimatedTile(tile);
00863 }
00864 break;
00865
00866 case GFX_COPPER_MINE_CHIMNEY:
00867 CreateEffectVehicleAbove(TileX(tile) * TILE_SIZE + 6, TileY(tile) * TILE_SIZE + 6, 43, EV_SMOKE);
00868 break;
00869
00870
00871 case GFX_TOY_FACTORY: {
00872 Industry *i = Industry::GetByTile(tile);
00873 if (i->was_cargo_delivered) {
00874 i->was_cargo_delivered = false;
00875 SetIndustryAnimationLoop(tile, 0);
00876 AddAnimatedTile(tile);
00877 }
00878 }
00879 break;
00880
00881 case GFX_BUBBLE_GENERATOR:
00882 TileLoopIndustry_BubbleGenerator(tile);
00883 break;
00884
00885 case GFX_TOFFEE_QUARY:
00886 AddAnimatedTile(tile);
00887 break;
00888
00889 case GFX_SUGAR_MINE_SIEVE:
00890 if (Chance16(1, 3)) AddAnimatedTile(tile);
00891 break;
00892 }
00893 }
00894
00895 static bool ClickTile_Industry(TileIndex tile)
00896 {
00897 ShowIndustryViewWindow(GetIndustryIndex(tile));
00898 return true;
00899 }
00900
00901 static TrackStatus GetTileTrackStatus_Industry(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
00902 {
00903 return 0;
00904 }
00905
00906 static void ChangeTileOwner_Industry(TileIndex tile, Owner old_owner, Owner new_owner)
00907 {
00908
00909 Industry *i = Industry::GetByTile(tile);
00910 if (i->founder == old_owner) i->founder = (new_owner == INVALID_OWNER) ? OWNER_NONE : new_owner;
00911 }
00912
00913 static const byte _plantfarmfield_type[] = {1, 1, 1, 1, 1, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6};
00914
00915 static bool IsBadFarmFieldTile(TileIndex tile)
00916 {
00917 switch (GetTileType(tile)) {
00918 case MP_CLEAR: return IsClearGround(tile, CLEAR_FIELDS) || IsClearGround(tile, CLEAR_SNOW) || IsClearGround(tile, CLEAR_DESERT);
00919 case MP_TREES: return (GetTreeGround(tile) == TREE_GROUND_SHORE);
00920 default: return true;
00921 }
00922 }
00923
00924 static bool IsBadFarmFieldTile2(TileIndex tile)
00925 {
00926 switch (GetTileType(tile)) {
00927 case MP_CLEAR: return IsClearGround(tile, CLEAR_SNOW) || IsClearGround(tile, CLEAR_DESERT);
00928 case MP_TREES: return (GetTreeGround(tile) == TREE_GROUND_SHORE);
00929 default: return true;
00930 }
00931 }
00932
00933 static void SetupFarmFieldFence(TileIndex tile, int size, byte type, Axis direction)
00934 {
00935 do {
00936 tile = TILE_MASK(tile);
00937
00938 if (IsTileType(tile, MP_CLEAR) || IsTileType(tile, MP_TREES)) {
00939 byte or_ = type;
00940
00941 if (or_ == 1 && Chance16(1, 7)) or_ = 2;
00942
00943 if (direction == AXIS_X) {
00944 SetFenceSE(tile, or_);
00945 } else {
00946 SetFenceSW(tile, or_);
00947 }
00948 }
00949
00950 tile += (direction == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
00951 } while (--size);
00952 }
00953
00954 static void PlantFarmField(TileIndex tile, IndustryID industry)
00955 {
00956 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
00957 if (GetTileZ(tile) + TILE_HEIGHT * 2 >= GetSnowLine()) return;
00958 }
00959
00960
00961 uint32 r = (Random() & 0x303) + 0x404;
00962 if (_settings_game.game_creation.landscape == LT_ARCTIC) r += 0x404;
00963 uint size_x = GB(r, 0, 8);
00964 uint size_y = GB(r, 8, 8);
00965
00966 TileArea ta(tile - TileDiffXY(min(TileX(tile), size_x / 2), min(TileY(tile), size_y / 2)), size_x, size_y);
00967 ta.ClampToMap();
00968
00969 if (ta.w == 0 || ta.h == 0) return;
00970
00971
00972 int count = 0;
00973 TILE_AREA_LOOP(cur_tile, ta) {
00974 assert(cur_tile < MapSize());
00975 count += IsBadFarmFieldTile(cur_tile);
00976 }
00977 if (count * 2 >= ta.w * ta.h) return;
00978
00979
00980 r = Random();
00981 uint counter = GB(r, 5, 3);
00982 uint field_type = GB(r, 8, 8) * 9 >> 8;
00983
00984
00985 TILE_AREA_LOOP(cur_tile, ta) {
00986 assert(cur_tile < MapSize());
00987 if (!IsBadFarmFieldTile2(cur_tile)) {
00988 MakeField(cur_tile, field_type, industry);
00989 SetClearCounter(cur_tile, counter);
00990 MarkTileDirtyByTile(cur_tile);
00991 }
00992 }
00993
00994 int type = 3;
00995 if (_settings_game.game_creation.landscape != LT_ARCTIC && _settings_game.game_creation.landscape != LT_TROPIC) {
00996 type = _plantfarmfield_type[Random() & 0xF];
00997 }
00998
00999 SetupFarmFieldFence(ta.tile - TileDiffXY(1, 0), ta.h, type, AXIS_Y);
01000 SetupFarmFieldFence(ta.tile - TileDiffXY(0, 1), ta.w, type, AXIS_X);
01001 SetupFarmFieldFence(ta.tile + TileDiffXY(ta.w - 1, 0), ta.h, type, AXIS_Y);
01002 SetupFarmFieldFence(ta.tile + TileDiffXY(0, ta.h - 1), ta.w, type, AXIS_X);
01003 }
01004
01005 void PlantRandomFarmField(const Industry *i)
01006 {
01007 int x = i->location.w / 2 + Random() % 31 - 16;
01008 int y = i->location.h / 2 + Random() % 31 - 16;
01009
01010 TileIndex tile = TileAddWrap(i->location.tile, x, y);
01011
01012 if (tile != INVALID_TILE) PlantFarmField(tile, i->index);
01013 }
01014
01021 static bool SearchLumberMillTrees(TileIndex tile, void *user_data)
01022 {
01023 if (IsTileType(tile, MP_TREES) && GetTreeGrowth(tile) > 2) {
01024
01025
01026 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
01027
01028 _industry_sound_ctr = 1;
01029 _industry_sound_tile = tile;
01030 SndPlayTileFx(SND_38_CHAINSAW, tile);
01031
01032 DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
01033
01034 cur_company.Restore();
01035 return true;
01036 }
01037 return false;
01038 }
01039
01044 static void ChopLumberMillTrees(Industry *i)
01045 {
01046 TileIndex tile = i->location.tile;
01047
01048 if (!IsIndustryCompleted(tile)) return;
01049
01050 if (CircularTileSearch(&tile, 40, SearchLumberMillTrees, NULL)) {
01051 i->produced_cargo_waiting[0] = min(0xffff, i->produced_cargo_waiting[0] + 45);
01052 }
01053 }
01054
01055 static void ProduceIndustryGoods(Industry *i)
01056 {
01057 const IndustrySpec *indsp = GetIndustrySpec(i->type);
01058
01059
01060 if ((i->counter & 0x3F) == 0) {
01061 uint32 r;
01062 uint num;
01063 if (Chance16R(1, 14, r) && (num = indsp->number_of_sounds) != 0) {
01064 SndPlayTileFx(
01065 (SoundFx)(indsp->random_sounds[((r >> 16) * num) >> 16]),
01066 i->location.tile);
01067 }
01068 }
01069
01070 i->counter--;
01071
01072
01073 if ((i->counter & 0xFF) == 0) {
01074 if (HasBit(indsp->callback_mask, CBM_IND_PRODUCTION_256_TICKS)) IndustryProductionCallback(i, 1);
01075
01076 IndustryBehaviour indbehav = indsp->behaviour;
01077 i->produced_cargo_waiting[0] = min(0xffff, i->produced_cargo_waiting[0] + i->production_rate[0]);
01078 i->produced_cargo_waiting[1] = min(0xffff, i->produced_cargo_waiting[1] + i->production_rate[1]);
01079
01080 if ((indbehav & INDUSTRYBEH_PLANT_FIELDS) != 0) {
01081 bool plant;
01082 if (HasBit(indsp->callback_mask, CBM_IND_SPECIAL_EFFECT)) {
01083 plant = (GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 0, i, i->type, i->location.tile) != 0);
01084 } else {
01085 plant = Chance16(1, 8);
01086 }
01087
01088 if (plant) PlantRandomFarmField(i);
01089 }
01090 if ((indbehav & INDUSTRYBEH_CUT_TREES) != 0) {
01091 bool cut = ((i->counter & 0x1FF) == 0);
01092 if (HasBit(indsp->callback_mask, CBM_IND_SPECIAL_EFFECT)) {
01093 cut = (GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, 0, 1, i, i->type, i->location.tile) != 0);
01094 }
01095
01096 if (cut) ChopLumberMillTrees(i);
01097 }
01098
01099 TriggerIndustry(i, INDUSTRY_TRIGGER_INDUSTRY_TICK);
01100 StartStopIndustryTileAnimation(i, IAT_INDUSTRY_TICK);
01101 }
01102 }
01103
01104 void OnTick_Industry()
01105 {
01106 if (_industry_sound_ctr != 0) {
01107 _industry_sound_ctr++;
01108
01109 if (_industry_sound_ctr == 75) {
01110 SndPlayTileFx(SND_37_BALLOON_SQUEAK, _industry_sound_tile);
01111 } else if (_industry_sound_ctr == 160) {
01112 _industry_sound_ctr = 0;
01113 SndPlayTileFx(SND_36_CARTOON_CRASH, _industry_sound_tile);
01114 }
01115 }
01116
01117 if (_game_mode == GM_EDITOR) return;
01118
01119 Industry *i;
01120 FOR_ALL_INDUSTRIES(i) {
01121 ProduceIndustryGoods(i);
01122 }
01123 }
01124
01130 static CommandCost CheckNewIndustry_NULL(TileIndex tile)
01131 {
01132 return CommandCost();
01133 }
01134
01140 static CommandCost CheckNewIndustry_Forest(TileIndex tile)
01141 {
01142 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
01143 if (GetTileZ(tile) < HighestSnowLine() + TILE_HEIGHT * 2U) {
01144 return_cmd_error(STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED);
01145 }
01146 }
01147 return CommandCost();
01148 }
01149
01155 static CommandCost CheckNewIndustry_OilRefinery(TileIndex tile)
01156 {
01157 if (_game_mode == GM_EDITOR) return CommandCost();
01158 if (DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _settings_game.game_creation.oil_refinery_limit) return CommandCost();
01159
01160 return_cmd_error(STR_ERROR_CAN_ONLY_BE_POSITIONED);
01161 }
01162
01163 extern bool _ignore_restrictions;
01164
01170 static CommandCost CheckNewIndustry_OilRig(TileIndex tile)
01171 {
01172 if (_game_mode == GM_EDITOR && _ignore_restrictions) return CommandCost();
01173 if (TileHeight(tile) == 0 &&
01174 DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _settings_game.game_creation.oil_refinery_limit) return CommandCost();
01175
01176 return_cmd_error(STR_ERROR_CAN_ONLY_BE_POSITIONED);
01177 }
01178
01184 static CommandCost CheckNewIndustry_Farm(TileIndex tile)
01185 {
01186 if (_settings_game.game_creation.landscape == LT_ARCTIC) {
01187 if (GetTileZ(tile) + TILE_HEIGHT * 2 >= HighestSnowLine()) {
01188 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
01189 }
01190 }
01191 return CommandCost();
01192 }
01193
01199 static CommandCost CheckNewIndustry_Plantation(TileIndex tile)
01200 {
01201 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
01202 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
01203 }
01204 return CommandCost();
01205 }
01206
01212 static CommandCost CheckNewIndustry_Water(TileIndex tile)
01213 {
01214 if (GetTropicZone(tile) != TROPICZONE_DESERT) {
01215 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT);
01216 }
01217 return CommandCost();
01218 }
01219
01225 static CommandCost CheckNewIndustry_Lumbermill(TileIndex tile)
01226 {
01227 if (GetTropicZone(tile) != TROPICZONE_RAINFOREST) {
01228 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST);
01229 }
01230 return CommandCost();
01231 }
01232
01238 static CommandCost CheckNewIndustry_BubbleGen(TileIndex tile)
01239 {
01240 if (GetTileZ(tile) > TILE_HEIGHT * 4) {
01241 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS);
01242 }
01243 return CommandCost();
01244 }
01245
01251 typedef CommandCost CheckNewIndustryProc(TileIndex tile);
01252
01254 static CheckNewIndustryProc * const _check_new_industry_procs[CHECK_END] = {
01255 CheckNewIndustry_NULL,
01256 CheckNewIndustry_Forest,
01257 CheckNewIndustry_OilRefinery,
01258 CheckNewIndustry_Farm,
01259 CheckNewIndustry_Plantation,
01260 CheckNewIndustry_Water,
01261 CheckNewIndustry_Lumbermill,
01262 CheckNewIndustry_BubbleGen,
01263 CheckNewIndustry_OilRig,
01264 };
01265
01276 static CommandCost FindTownForIndustry(TileIndex tile, int type, const Town **t)
01277 {
01278 *t = ClosestTownFromTile(tile, UINT_MAX);
01279
01280 if (_settings_game.economy.multiple_industry_per_town) return CommandCost();
01281
01282 const Industry *i;
01283 FOR_ALL_INDUSTRIES(i) {
01284 if (i->type == (byte)type && i->town == *t) {
01285 *t = NULL;
01286 return_cmd_error(STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN);
01287 }
01288 }
01289
01290 return CommandCost();
01291 }
01292
01293 bool IsSlopeRefused(Slope current, Slope refused)
01294 {
01295 if (IsSteepSlope(current)) return true;
01296 if (current != SLOPE_FLAT) {
01297 if (IsSteepSlope(refused)) return true;
01298
01299 Slope t = ComplementSlope(current);
01300
01301 if ((refused & SLOPE_W) && (t & SLOPE_NW)) return true;
01302 if ((refused & SLOPE_S) && (t & SLOPE_NE)) return true;
01303 if ((refused & SLOPE_E) && (t & SLOPE_SW)) return true;
01304 if ((refused & SLOPE_N) && (t & SLOPE_SE)) return true;
01305 }
01306
01307 return false;
01308 }
01309
01322 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)
01323 {
01324 bool refused_slope = false;
01325 bool custom_shape = false;
01326
01327 do {
01328 IndustryGfx gfx = GetTranslatedIndustryTileID(it->gfx);
01329 TileIndex cur_tile = TileAddWrap(tile, it->ti.x, it->ti.y);
01330
01331 if (!IsValidTile(cur_tile)) {
01332 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
01333 }
01334
01335 if (gfx == GFX_WATERTILE_SPECIALCHECK) {
01336 if (!IsTileType(cur_tile, MP_WATER) ||
01337 GetTileSlope(cur_tile, NULL) != SLOPE_FLAT) {
01338 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
01339 }
01340 } else {
01341 CommandCost ret = EnsureNoVehicleOnGround(cur_tile);
01342 if (ret.Failed()) return ret;
01343 if (MayHaveBridgeAbove(cur_tile) && IsBridgeAbove(cur_tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
01344
01345 const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
01346
01347 IndustryBehaviour ind_behav = GetIndustrySpec(type)->behaviour;
01348
01349
01350 if (!HasBit(its->slopes_refused, 5) && ((HasTileWaterClass(cur_tile) && IsTileOnWater(cur_tile)) == !(ind_behav & INDUSTRYBEH_BUILT_ONWATER))) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
01351
01352 if (HasBit(its->callback_mask, CBM_INDT_SHAPE_CHECK)) {
01353 custom_shape = true;
01354 CommandCost ret = PerformIndustryTileSlopeCheck(tile, cur_tile, its, type, gfx, itspec_index, initial_random_bits, founder, creation_type);
01355 if (ret.Failed()) return ret;
01356 } else {
01357 Slope tileh = GetTileSlope(cur_tile, NULL);
01358 refused_slope |= IsSlopeRefused(tileh, its->slopes_refused);
01359 }
01360
01361 if ((ind_behav & (INDUSTRYBEH_ONLY_INTOWN | INDUSTRYBEH_TOWN1200_MORE)) ||
01362 ((ind_behav & INDUSTRYBEH_ONLY_NEARTOWN) && IsTileType(cur_tile, MP_HOUSE))) {
01363 if (!IsTileType(cur_tile, MP_HOUSE)) {
01364 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS);
01365 }
01366
01367
01368 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
01369 CommandCost ret = DoCommand(cur_tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR);
01370 cur_company.Restore();
01371
01372 if (ret.Failed()) return ret;
01373 } else {
01374
01375 CommandCost ret = DoCommand(cur_tile, 0, 0, DC_AUTO | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR);
01376
01377 if (ret.Failed()) return ret;
01378 }
01379 }
01380 } while ((++it)->ti.x != -0x80);
01381
01382 if (custom_shape_check != NULL) *custom_shape_check = custom_shape;
01383
01384
01385
01386
01387 if (!refused_slope || (_settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world && !custom_shape && !_ignore_restrictions)) {
01388 return CommandCost();
01389 }
01390 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
01391 }
01392
01400 static CommandCost CheckIfIndustryIsAllowed(TileIndex tile, int type, const Town *t)
01401 {
01402 if ((GetIndustrySpec(type)->behaviour & INDUSTRYBEH_TOWN1200_MORE) && t->population < 1200) {
01403 return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200);
01404 }
01405
01406 if ((GetIndustrySpec(type)->behaviour & INDUSTRYBEH_ONLY_NEARTOWN) && DistanceMax(t->xy, tile) > 9) {
01407 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
01408 }
01409
01410 return CommandCost();
01411 }
01412
01413 static bool CheckCanTerraformSurroundingTiles(TileIndex tile, uint height, int internal)
01414 {
01415
01416 if (TileX(tile) == 0 || TileY(tile) == 0 || GetTileType(tile) == MP_VOID) return false;
01417
01418 TileArea ta(tile - TileDiffXY(1, 1), 2, 2);
01419 TILE_AREA_LOOP(tile_walk, ta) {
01420 uint curh = TileHeight(tile_walk);
01421
01422 if ((GetTileType(tile_walk) != MP_CLEAR) && (GetTileType(tile_walk) != MP_TREES)) return false;
01423
01424
01425 if (internal != 0 && Delta(curh, height) > 1) return false;
01426
01427
01428
01429
01430 if (internal == 0 && curh != height) {
01431 if (TileX(tile_walk) == 0 || TileY(tile_walk) == 0 || !CheckCanTerraformSurroundingTiles(tile_walk + TileDiffXY(-1, -1), height, internal + 1)) {
01432 return false;
01433 }
01434 }
01435 }
01436
01437 return true;
01438 }
01439
01444 static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, DoCommandFlag flags, const IndustryTileTable *it, int type)
01445 {
01446 const int MKEND = -0x80;
01447 int max_x = 0;
01448 int max_y = 0;
01449
01450
01451 do {
01452 if (it->gfx == 0xFF) continue;
01453 if (it->ti.x > max_x) max_x = it->ti.x;
01454 if (it->ti.y > max_y) max_y = it->ti.y;
01455 } while ((++it)->ti.x != MKEND);
01456
01457
01458 uint h = TileHeight(tile);
01459
01460 if (TileX(tile) <= _settings_game.construction.industry_platform + 1U || TileY(tile) <= _settings_game.construction.industry_platform + 1U) return false;
01461
01462
01463
01464 TileArea ta(tile + TileDiffXY(-_settings_game.construction.industry_platform, -_settings_game.construction.industry_platform),
01465 max_x + 2 + 2 * _settings_game.construction.industry_platform, max_y + 2 + 2 * _settings_game.construction.industry_platform);
01466
01467 if (TileX(ta.tile) + ta.w >= MapMaxX() || TileY(ta.tile) + ta.h >= MapMaxY()) return false;
01468
01469
01470
01471 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
01472
01473 TILE_AREA_LOOP(tile_walk, ta) {
01474 uint curh = TileHeight(tile_walk);
01475 if (curh != h) {
01476
01477
01478 if (!CheckCanTerraformSurroundingTiles(tile_walk, h, 0)) {
01479 cur_company.Restore();
01480 return false;
01481 }
01482
01483
01484 if (DoCommand(tile_walk, SLOPE_N, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND).Failed()) {
01485 cur_company.Restore();
01486 return false;
01487 }
01488 }
01489 }
01490
01491 if (flags & DC_EXEC) {
01492
01493 TILE_AREA_LOOP(tile_walk, ta) {
01494 uint curh = TileHeight(tile_walk);
01495 while (curh != h) {
01496
01497
01498
01499 DoCommand(tile_walk, SLOPE_N, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND);
01500 curh += (curh > h) ? -1 : 1;
01501 }
01502 }
01503 }
01504
01505 cur_company.Restore();
01506 return true;
01507 }
01508
01509
01516 static CommandCost CheckIfFarEnoughFromConflictingIndustry(TileIndex tile, int type)
01517 {
01518 const IndustrySpec *indspec = GetIndustrySpec(type);
01519 const Industry *i;
01520 FOR_ALL_INDUSTRIES(i) {
01521
01522 if (DistanceMax(tile, i->location.tile) > 14) continue;
01523
01524
01525 if (i->type == indspec->conflicting[0] ||
01526 i->type == indspec->conflicting[1] ||
01527 i->type == indspec->conflicting[2]) {
01528 return_cmd_error(STR_ERROR_INDUSTRY_TOO_CLOSE);
01529 }
01530 }
01531 return CommandCost();
01532 }
01533
01545 static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, const IndustryTileTable *it, byte layout, const Town *t, Owner founder, uint16 initial_random_bits)
01546 {
01547 const IndustrySpec *indspec = GetIndustrySpec(type);
01548
01549 i->location = TileArea(tile, 1, 1);
01550 i->type = type;
01551 Industry::IncIndustryTypeCount(type);
01552
01553 i->produced_cargo[0] = indspec->produced_cargo[0];
01554 i->produced_cargo[1] = indspec->produced_cargo[1];
01555 i->accepts_cargo[0] = indspec->accepts_cargo[0];
01556 i->accepts_cargo[1] = indspec->accepts_cargo[1];
01557 i->accepts_cargo[2] = indspec->accepts_cargo[2];
01558 i->production_rate[0] = indspec->production_rate[0];
01559 i->production_rate[1] = indspec->production_rate[1];
01560
01561
01562 if (indspec->UsesSmoothEconomy()) {
01563 i->production_rate[0] = min((RandomRange(256) + 128) * i->production_rate[0] >> 8, 255);
01564 i->production_rate[1] = min((RandomRange(256) + 128) * i->production_rate[1] >> 8, 255);
01565 }
01566
01567 i->town = t;
01568 i->owner = OWNER_NONE;
01569
01570 uint16 r = Random();
01571 i->random_colour = GB(r, 0, 4);
01572 i->counter = GB(r, 4, 12);
01573 i->random = initial_random_bits;
01574 i->produced_cargo_waiting[0] = 0;
01575 i->produced_cargo_waiting[1] = 0;
01576 i->incoming_cargo_waiting[0] = 0;
01577 i->incoming_cargo_waiting[1] = 0;
01578 i->incoming_cargo_waiting[2] = 0;
01579 i->this_month_production[0] = 0;
01580 i->this_month_production[1] = 0;
01581 i->this_month_transported[0] = 0;
01582 i->this_month_transported[1] = 0;
01583 i->last_month_pct_transported[0] = 0;
01584 i->last_month_pct_transported[1] = 0;
01585 i->last_month_transported[0] = 0;
01586 i->last_month_transported[1] = 0;
01587 i->was_cargo_delivered = false;
01588 i->last_prod_year = _cur_year;
01589 i->last_month_production[0] = i->production_rate[0] * 8;
01590 i->last_month_production[1] = i->production_rate[1] * 8;
01591 i->founder = founder;
01592
01593 i->construction_date = _date;
01594 i->construction_type = (_game_mode == GM_EDITOR) ? ICT_SCENARIO_EDITOR :
01595 (_generating_world ? ICT_MAP_GENERATION : ICT_NORMAL_GAMEPLAY);
01596
01597
01598
01599
01600 i->selected_layout = layout + 1;
01601
01602 if (!_generating_world) i->last_month_production[0] = i->last_month_production[1] = 0;
01603
01604 i->prod_level = PRODLEVEL_DEFAULT;
01605
01606
01607
01608 if (HasBit(indspec->callback_mask, CBM_IND_DECIDE_COLOUR)) {
01609 uint16 res = GetIndustryCallback(CBID_INDUSTRY_DECIDE_COLOUR, 0, 0, i, type, INVALID_TILE);
01610 if (res != CALLBACK_FAILED) i->random_colour = GB(res, 0, 4);
01611 }
01612
01613 if (HasBit(indspec->callback_mask, CBM_IND_INPUT_CARGO_TYPES)) {
01614 for (uint j = 0; j < lengthof(i->accepts_cargo); j++) i->accepts_cargo[j] = CT_INVALID;
01615 for (uint j = 0; j < lengthof(i->accepts_cargo); j++) {
01616 uint16 res = GetIndustryCallback(CBID_INDUSTRY_INPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE);
01617 if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
01618 i->accepts_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
01619 }
01620 }
01621
01622 if (HasBit(indspec->callback_mask, CBM_IND_OUTPUT_CARGO_TYPES)) {
01623 for (uint j = 0; j < lengthof(i->produced_cargo); j++) i->produced_cargo[j] = CT_INVALID;
01624 for (uint j = 0; j < lengthof(i->produced_cargo); j++) {
01625 uint16 res = GetIndustryCallback(CBID_INDUSTRY_OUTPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE);
01626 if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
01627 i->produced_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
01628 }
01629 }
01630
01631
01632
01633 do {
01634 TileIndex cur_tile = tile + ToTileIndexDiff(it->ti);
01635
01636 if (it->gfx != GFX_WATERTILE_SPECIALCHECK) {
01637 i->location.Add(cur_tile);
01638
01639 WaterClass wc = (IsWaterTile(cur_tile) ? GetWaterClass(cur_tile) : WATER_CLASS_INVALID);
01640
01641 DoCommand(cur_tile, 0, 0, DC_EXEC | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR);
01642
01643 MakeIndustry(cur_tile, i->index, it->gfx, Random(), wc);
01644
01645 if (_generating_world) {
01646 SetIndustryConstructionCounter(cur_tile, 3);
01647 SetIndustryConstructionStage(cur_tile, 2);
01648 }
01649
01650
01651 IndustryGfx cur_gfx = GetTranslatedIndustryTileID(it->gfx);
01652 const IndustryTileSpec *its = GetIndustryTileSpec(cur_gfx);
01653 if (its->animation.status != ANIM_STATUS_NO_ANIMATION) AddAnimatedTile(cur_tile);
01654 }
01655 } while ((++it)->ti.x != -0x80);
01656
01657 if (GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_PLANT_ON_BUILT) {
01658 for (uint j = 0; j != 50; j++) PlantRandomFarmField(i);
01659 }
01660 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0);
01661
01662 Station::RecomputeIndustriesNearForAll();
01663 }
01664
01681 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)
01682 {
01683 assert(itspec_index < indspec->num_table);
01684 const IndustryTileTable *it = indspec->table[itspec_index];
01685 bool custom_shape_check = false;
01686
01687 *ip = NULL;
01688
01689 SmallVector<ClearedObjectArea, 1> object_areas(_cleared_object_areas);
01690 CommandCost ret = CheckIfIndustryTilesAreFree(tile, it, itspec_index, type, random_initial_bits, founder, creation_type, &custom_shape_check);
01691 _cleared_object_areas = object_areas;
01692 if (ret.Failed()) return ret;
01693
01694 if (HasBit(GetIndustrySpec(type)->callback_mask, CBM_IND_LOCATION)) {
01695 ret = CheckIfCallBackAllowsCreation(tile, type, itspec_index, random_var8f, random_initial_bits, founder, creation_type);
01696 } else {
01697 ret = _check_new_industry_procs[indspec->check_proc](tile);
01698 }
01699 if (ret.Failed()) return ret;
01700
01701 if (!custom_shape_check && _settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world &&
01702 !_ignore_restrictions && !CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER, it, type)) {
01703 return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
01704 }
01705
01706 ret = CheckIfFarEnoughFromConflictingIndustry(tile, type);
01707 if (ret.Failed()) return ret;
01708
01709 const Town *t = NULL;
01710 ret = FindTownForIndustry(tile, type, &t);
01711 if (ret.Failed()) return ret;
01712 assert(t != NULL);
01713
01714 ret = CheckIfIndustryIsAllowed(tile, type, t);
01715 if (ret.Failed()) return ret;
01716
01717 if (!Industry::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_INDUSTRIES);
01718
01719 if (flags & DC_EXEC) {
01720 *ip = new Industry(tile);
01721 if (!custom_shape_check) CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER | DC_EXEC, it, type);
01722 DoCreateNewIndustry(*ip, tile, type, it, itspec_index, t, founder, random_initial_bits);
01723 }
01724
01725 return CommandCost();
01726 }
01727
01739 CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01740 {
01741 IndustryType it = GB(p1, 0, 8);
01742 if (it >= NUM_INDUSTRYTYPES) return CMD_ERROR;
01743
01744 const IndustrySpec *indspec = GetIndustrySpec(it);
01745
01746
01747 if (!indspec->enabled || indspec->num_table == 0) return CMD_ERROR;
01748
01749
01750
01751 if (_game_mode != GM_EDITOR && _settings_game.construction.raw_industry_construction == 0 && indspec->IsRawIndustry()) {
01752 return CMD_ERROR;
01753 }
01754
01755 if (_game_mode != GM_EDITOR && !CheckIfCallBackAllowsAvailability(it, IACT_USERCREATION)) {
01756 return CMD_ERROR;
01757 }
01758
01759 Randomizer randomizer;
01760 randomizer.SetSeed(p2);
01761 uint16 random_initial_bits = GB(p2, 0, 16);
01762 uint32 random_var8f = randomizer.Next();
01763
01764 Industry *ind = NULL;
01765 if (_game_mode != GM_EDITOR && _settings_game.construction.raw_industry_construction == 2 && indspec->IsRawIndustry()) {
01766 if (flags & DC_EXEC) {
01767
01768 Backup<CompanyByte> cur_company(_current_company, OWNER_TOWN, FILE_LINE);
01769
01770
01771
01772 if (Random() <= indspec->prospecting_chance) {
01773 for (int i = 0; i < 5000; i++) {
01774
01775
01776
01777 tile = RandomTile();
01778 CommandCost ret = CreateNewIndustryHelper(tile, it, flags, indspec, RandomRange(indspec->num_table), random_var8f, random_initial_bits, cur_company.GetOriginalValue(), IACT_PROSPECTCREATION, &ind);
01779 if (ret.Succeeded()) break;
01780 }
01781 }
01782 cur_company.Restore();
01783 }
01784 } else {
01785 int count = indspec->num_table;
01786 const IndustryTileTable * const *itt = indspec->table;
01787 int num = GB(p1, 8, 8);
01788 if (num >= count) return CMD_ERROR;
01789
01790 CommandCost ret = CommandCost(STR_ERROR_SITE_UNSUITABLE);
01791 SmallVector<ClearedObjectArea, 1> object_areas(_cleared_object_areas);
01792 do {
01793 if (--count < 0) return ret;
01794 if (--num < 0) num = indspec->num_table - 1;
01795 ret = CheckIfIndustryTilesAreFree(tile, itt[num], num, it, random_initial_bits, _current_company, IACT_USERCREATION);
01796 _cleared_object_areas = object_areas;
01797 } while (ret.Failed());
01798
01799 ret = CreateNewIndustryHelper(tile, it, flags, indspec, num, random_var8f, random_initial_bits, _current_company, IACT_USERCREATION, &ind);
01800 if (ret.Failed()) return ret;
01801 }
01802
01803 if ((flags & DC_EXEC) && ind != NULL && _game_mode != GM_EDITOR) {
01804
01805 SetDParam(0, indspec->name);
01806 if (indspec->new_industry_text > STR_LAST_STRINGID) {
01807 SetDParam(1, STR_TOWN_NAME);
01808 SetDParam(2, ind->town->index);
01809 } else {
01810 SetDParam(1, ind->town->index);
01811 }
01812 AddIndustryNewsItem(indspec->new_industry_text, NS_INDUSTRY_OPEN, ind->index);
01813 AI::BroadcastNewEvent(new AIEventIndustryOpen(ind->index));
01814 }
01815
01816 return CommandCost(EXPENSES_OTHER, indspec->GetConstructionCost());
01817 }
01818
01819
01827 static Industry *CreateNewIndustry(TileIndex tile, IndustryType type, IndustryAvailabilityCallType creation_type)
01828 {
01829 const IndustrySpec *indspec = GetIndustrySpec(type);
01830
01831 uint32 seed = Random();
01832 uint32 seed2 = Random();
01833 Industry *i = NULL;
01834 CommandCost ret = CreateNewIndustryHelper(tile, type, DC_EXEC, indspec, RandomRange(indspec->num_table), seed, GB(seed2, 0, 16), OWNER_NONE, creation_type, &i);
01835 assert(i != NULL || ret.Failed());
01836 return i;
01837 }
01838
01845 static uint32 GetScaledIndustryGenerationProbability(IndustryType it, bool *force_at_least_one)
01846 {
01847 const IndustrySpec *ind_spc = GetIndustrySpec(it);
01848 uint32 chance = ind_spc->appear_creation[_settings_game.game_creation.landscape] * 16;
01849 if (!ind_spc->enabled || chance == 0 || ind_spc->num_table == 0 ||
01850 !CheckIfCallBackAllowsAvailability(it, IACT_MAPGENERATION) ||
01851 (_game_mode != GM_EDITOR && _settings_game.difficulty.number_industries == 0)) {
01852 *force_at_least_one = false;
01853 return 0;
01854 } else {
01855
01856
01857 chance = (ind_spc->check_proc == CHECK_REFINERY || ind_spc->check_proc == CHECK_OIL_RIG) ? ScaleByMapSize1D(chance) : ScaleByMapSize(chance);
01858
01859 *force_at_least_one = (chance > 0) && !(ind_spc->behaviour & INDUSTRYBEH_NOBUILT_MAPCREATION) && (_game_mode != GM_EDITOR);
01860 return chance;
01861 }
01862 }
01863
01870 static uint16 GetIndustryGamePlayProbability(IndustryType it, byte *min_number)
01871 {
01872 if (_settings_game.difficulty.number_industries == 0) {
01873 *min_number = 0;
01874 return 0;
01875 }
01876
01877 const IndustrySpec *ind_spc = GetIndustrySpec(it);
01878 byte chance = ind_spc->appear_ingame[_settings_game.game_creation.landscape];
01879 if (!ind_spc->enabled || chance == 0 || ind_spc->num_table == 0 ||
01880 ((ind_spc->behaviour & INDUSTRYBEH_BEFORE_1950) && _cur_year > 1950) ||
01881 ((ind_spc->behaviour & INDUSTRYBEH_AFTER_1960) && _cur_year < 1960) ||
01882 !CheckIfCallBackAllowsAvailability(it, IACT_RANDOMCREATION)) {
01883 *min_number = 0;
01884 return 0;
01885 }
01886 *min_number = (ind_spc->behaviour & INDUSTRYBEH_CANCLOSE_LASTINSTANCE) ? 1 : 0;
01887 return chance;
01888 }
01889
01894 static uint GetNumberOfIndustries()
01895 {
01896
01897 static const uint16 numof_industry_table[] = {
01898 0,
01899 10,
01900 25,
01901 55,
01902 80,
01903 };
01904
01905 assert(_settings_game.difficulty.number_industries < lengthof(numof_industry_table));
01906 uint difficulty = (_game_mode != GM_EDITOR) ? _settings_game.difficulty.number_industries : 1;
01907 return ScaleByMapSize(numof_industry_table[difficulty]);
01908 }
01909
01914 static void AdvertiseIndustryOpening(const Industry *ind)
01915 {
01916 const IndustrySpec *ind_spc = GetIndustrySpec(ind->type);
01917 SetDParam(0, ind_spc->name);
01918 if (ind_spc->new_industry_text > STR_LAST_STRINGID) {
01919 SetDParam(1, STR_TOWN_NAME);
01920 SetDParam(2, ind->town->index);
01921 } else {
01922 SetDParam(1, ind->town->index);
01923 }
01924 AddIndustryNewsItem(ind_spc->new_industry_text, NS_INDUSTRY_OPEN, ind->index);
01925 AI::BroadcastNewEvent(new AIEventIndustryOpen(ind->index));
01926 }
01927
01936 static Industry *PlaceIndustry(IndustryType type, IndustryAvailabilityCallType creation_type, bool try_hard)
01937 {
01938 uint tries = try_hard ? 10000u : 2000u;
01939 for (; tries > 0; tries--) {
01940 Industry *ind = CreateNewIndustry(RandomTile(), type, creation_type);
01941 if (ind != NULL) return ind;
01942 }
01943 return NULL;
01944 }
01945
01951 static void PlaceInitialIndustry(IndustryType type, bool try_hard)
01952 {
01953 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
01954
01955 IncreaseGeneratingWorldProgress(GWP_INDUSTRY);
01956 PlaceIndustry(type, IACT_MAPGENERATION, try_hard);
01957
01958 cur_company.Restore();
01959 }
01960
01965 static uint GetCurrentTotalNumberOfIndustries()
01966 {
01967 int total = 0;
01968 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) total += Industry::GetIndustryTypeCount(it);
01969 return total;
01970 }
01971
01972
01974 void IndustryTypeBuildData::Reset()
01975 {
01976 this->probability = 0;
01977 this->min_number = 0;
01978 this->target_count = 0;
01979 this->max_wait = 1;
01980 this->wait_count = 0;
01981 }
01982
01984 void IndustryBuildData::Reset()
01985 {
01986 this->wanted_inds = GetCurrentTotalNumberOfIndustries() << 16;
01987
01988 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
01989 this->builddata[it].Reset();
01990 }
01991 }
01992
01994 void IndustryBuildData::MonthlyLoop()
01995 {
01996 static const int NEWINDS_PER_MONTH = 0x38000 / (10 * 12);
01997 if (_settings_game.difficulty.number_industries == 0) return;
01998
01999
02000
02001 uint max_behind = 1 + min(99u, ScaleByMapSize(3));
02002 if (GetCurrentTotalNumberOfIndustries() + max_behind >= (this->wanted_inds >> 16)) {
02003 this->wanted_inds += ScaleByMapSize(NEWINDS_PER_MONTH);
02004 }
02005 }
02006
02011 void GenerateIndustries()
02012 {
02013 uint total_amount = GetNumberOfIndustries();
02014
02015
02016 if (total_amount == 0) return;
02017
02018 uint32 industry_probs[NUM_INDUSTRYTYPES];
02019 bool force_at_least_one[NUM_INDUSTRYTYPES];
02020 uint32 total_prob = 0;
02021 uint num_forced = 0;
02022
02023 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
02024 industry_probs[it] = GetScaledIndustryGenerationProbability(it, force_at_least_one + it);
02025 total_prob += industry_probs[it];
02026 if (force_at_least_one[it]) num_forced++;
02027 }
02028
02029 if (total_prob == 0 || total_amount < num_forced) {
02030
02031 total_amount = num_forced;
02032 }
02033
02034 SetGeneratingWorldProgress(GWP_INDUSTRY, total_amount);
02035
02036
02037 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
02038 if (force_at_least_one[it]) {
02039 assert(total_amount > 0);
02040 total_amount--;
02041 PlaceInitialIndustry(it, true);
02042 }
02043 }
02044
02045
02046 for (uint i = 0; i < total_amount; i++) {
02047 uint32 r = RandomRange(total_prob);
02048 IndustryType it = 0;
02049 while (r >= industry_probs[it]) {
02050 r -= industry_probs[it];
02051 it++;
02052 assert(it < NUM_INDUSTRYTYPES);
02053 }
02054 assert(industry_probs[it] > 0);
02055 PlaceInitialIndustry(it, false);
02056 }
02057 _industry_builder.Reset();
02058 }
02059
02064 static void UpdateIndustryStatistics(Industry *i)
02065 {
02066 for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
02067 if (i->produced_cargo[j] != CT_INVALID) {
02068 byte pct = 0;
02069 if (i->this_month_production[j] != 0) {
02070 i->last_prod_year = _cur_year;
02071 pct = min(i->this_month_transported[j] * 256 / i->this_month_production[j], 255);
02072 }
02073 i->last_month_pct_transported[j] = pct;
02074
02075 i->last_month_production[j] = i->this_month_production[j];
02076 i->this_month_production[j] = 0;
02077
02078 i->last_month_transported[j] = i->this_month_transported[j];
02079 i->this_month_transported[j] = 0;
02080 }
02081 }
02082 }
02083
02088 void Industry::RecomputeProductionMultipliers()
02089 {
02090 const IndustrySpec *indspec = GetIndustrySpec(this->type);
02091 assert(!indspec->UsesSmoothEconomy());
02092
02093
02094 this->production_rate[0] = min(CeilDiv(indspec->production_rate[0] * this->prod_level, PRODLEVEL_DEFAULT), 0xFF);
02095 this->production_rate[1] = min(CeilDiv(indspec->production_rate[1] * this->prod_level, PRODLEVEL_DEFAULT), 0xFF);
02096 }
02097
02098
02104 bool IndustryTypeBuildData::GetIndustryTypeData(IndustryType it)
02105 {
02106 byte min_number;
02107 uint32 probability = GetIndustryGamePlayProbability(it, &min_number);
02108 bool changed = min_number != this->min_number || probability != this->probability;
02109 this->min_number = min_number;
02110 this->probability = probability;
02111 return changed;
02112 }
02113
02115 void IndustryBuildData::SetupTargetCount()
02116 {
02117 bool changed = false;
02118 uint num_planned = 0;
02119 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
02120 changed |= this->builddata[it].GetIndustryTypeData(it);
02121 num_planned += this->builddata[it].target_count;
02122 }
02123 uint total_amount = this->wanted_inds >> 16;
02124 changed |= num_planned != total_amount;
02125 if (!changed) return;
02126
02127
02128 uint force_build = 0;
02129 uint32 total_prob = 0;
02130 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
02131 IndustryTypeBuildData *ibd = this->builddata + it;
02132 force_build += ibd->min_number;
02133 ibd->target_count = ibd->min_number;
02134 total_prob += ibd->probability;
02135 }
02136
02137 if (total_prob == 0) return;
02138
02139
02140 total_amount = (total_amount <= force_build) ? 0 : total_amount - force_build;
02141
02142
02143 while (total_amount > 0) {
02144 uint32 r = RandomRange(total_prob);
02145 IndustryType it = 0;
02146 while (r >= this->builddata[it].probability) {
02147 r -= this->builddata[it].probability;
02148 it++;
02149 assert(it < NUM_INDUSTRYTYPES);
02150 }
02151 assert(this->builddata[it].probability > 0);
02152 this->builddata[it].target_count++;
02153 total_amount--;
02154 }
02155 }
02156
02160 void IndustryBuildData::TryBuildNewIndustry()
02161 {
02162 this->SetupTargetCount();
02163
02164 int missing = 0;
02165 uint count = 0;
02166 uint32 total_prob = 0;
02167 IndustryType forced_build = NUM_INDUSTRYTYPES;
02168 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
02169 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
02170 missing += difference;
02171 if (this->builddata[it].wait_count > 0) continue;
02172 if (difference > 0) {
02173 if (Industry::GetIndustryTypeCount(it) == 0 && this->builddata[it].min_number > 0) {
02174
02175 if (forced_build == NUM_INDUSTRYTYPES ||
02176 difference > this->builddata[forced_build].target_count - Industry::GetIndustryTypeCount(forced_build)) {
02177 forced_build = it;
02178 }
02179 }
02180 total_prob += difference;
02181 count++;
02182 }
02183 }
02184
02185 if (EconomyIsInRecession() || (forced_build == NUM_INDUSTRYTYPES && (missing <= 0 || total_prob == 0))) count = 0;
02186
02187 if (count >= 1) {
02188
02189
02190 IndustryType it;
02191 if (forced_build != NUM_INDUSTRYTYPES) {
02192 it = forced_build;
02193 } else {
02194
02195 uint32 r = 0;
02196 if (count > 1) r = RandomRange(total_prob);
02197 for (it = 0; it < NUM_INDUSTRYTYPES; it++) {
02198 if (this->builddata[it].wait_count > 0) continue;
02199 int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it);
02200 if (difference <= 0) continue;
02201 if (count == 1) break;
02202 if (r < (uint)difference) break;
02203 r -= difference;
02204 }
02205 assert(it < NUM_INDUSTRYTYPES && this->builddata[it].target_count > Industry::GetIndustryTypeCount(it));
02206 }
02207
02208
02209 const Industry *ind = PlaceIndustry(it, IACT_RANDOMCREATION, false);
02210 if (ind == NULL) {
02211 this->builddata[it].wait_count = this->builddata[it].max_wait + 1;
02212 this->builddata[it].max_wait = min(1000, this->builddata[it].max_wait + 2);
02213 } else {
02214 AdvertiseIndustryOpening(ind);
02215 this->builddata[it].max_wait = max(this->builddata[it].max_wait / 2, 1);
02216 }
02217 }
02218
02219
02220 for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) {
02221 if (this->builddata[it].wait_count > 0) this->builddata[it].wait_count--;
02222 }
02223 }
02224
02233 static bool CheckIndustryCloseDownProtection(IndustryType type)
02234 {
02235 const IndustrySpec *indspec = GetIndustrySpec(type);
02236
02237
02238 if ((indspec->behaviour & INDUSTRYBEH_DONT_INCR_PROD) && _settings_game.game_creation.landscape == LT_TEMPERATE) return false;
02239 return (indspec->behaviour & INDUSTRYBEH_CANCLOSE_LASTINSTANCE) == 0 && Industry::GetIndustryTypeCount(type) <= 1;
02240 }
02241
02251 static void CanCargoServiceIndustry(CargoID cargo, Industry *ind, bool *c_accepts, bool *c_produces)
02252 {
02253 if (cargo == CT_INVALID) return;
02254
02255
02256 for (byte j = 0; j < lengthof(ind->accepts_cargo); j++) {
02257 if (cargo == ind->accepts_cargo[j] && !IndustryTemporarilyRefusesCargo(ind, cargo)) {
02258 *c_accepts = true;
02259 break;
02260 }
02261 }
02262
02263
02264 for (byte j = 0; j < lengthof(ind->produced_cargo); j++) {
02265 if (cargo == ind->produced_cargo[j]) {
02266 *c_produces = true;
02267 break;
02268 }
02269 }
02270 }
02271
02285 static int WhoCanServiceIndustry(Industry *ind)
02286 {
02287
02288 StationList stations;
02289 FindStationsAroundTiles(ind->location, &stations);
02290
02291 if (stations.Length() == 0) return 0;
02292
02293 const Vehicle *v;
02294 int result = 0;
02295 FOR_ALL_VEHICLES(v) {
02296
02297 if (v->owner != _local_company && result != 0) continue;
02298
02299
02300 bool c_accepts = false;
02301 bool c_produces = false;
02302 if (v->type == VEH_TRAIN && Train::From(v)->IsFrontEngine()) {
02303 for (const Vehicle *u = v; u != NULL; u = u->Next()) {
02304 CanCargoServiceIndustry(u->cargo_type, ind, &c_accepts, &c_produces);
02305 }
02306 } else if (v->type == VEH_ROAD || v->type == VEH_SHIP || v->type == VEH_AIRCRAFT) {
02307 CanCargoServiceIndustry(v->cargo_type, ind, &c_accepts, &c_produces);
02308 } else {
02309 continue;
02310 }
02311 if (!c_accepts && !c_produces) continue;
02312
02313
02314
02315
02316
02317 const Order *o;
02318 FOR_VEHICLE_ORDERS(v, o) {
02319 if (o->IsType(OT_GOTO_STATION) && !(o->GetUnloadType() & OUFB_TRANSFER)) {
02320
02321 Station *st = Station::Get(o->GetDestination());
02322 assert(st != NULL);
02323
02324
02325 if ((o->GetUnloadType() & OUFB_UNLOAD) && !c_accepts) break;
02326
02327 if (stations.Contains(st)) {
02328 if (v->owner == _local_company) return 2;
02329 result = 1;
02330 }
02331 }
02332 }
02333 }
02334 return result;
02335 }
02336
02344 static void ReportNewsProductionChangeIndustry(Industry *ind, CargoID type, int percent)
02345 {
02346 NewsSubtype ns;
02347
02348 switch (WhoCanServiceIndustry(ind)) {
02349 case 0: ns = NS_INDUSTRY_NOBODY; break;
02350 case 1: ns = NS_INDUSTRY_OTHER; break;
02351 case 2: ns = NS_INDUSTRY_COMPANY; break;
02352 default: NOT_REACHED();
02353 }
02354 SetDParam(2, abs(percent));
02355 SetDParam(0, CargoSpec::Get(type)->name);
02356 SetDParam(1, ind->index);
02357 AddIndustryNewsItem(
02358 percent >= 0 ? STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH : STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH,
02359 ns,
02360 ind->index
02361 );
02362 }
02363
02364 static const uint PERCENT_TRANSPORTED_60 = 153;
02365 static const uint PERCENT_TRANSPORTED_80 = 204;
02366
02372 static void ChangeIndustryProduction(Industry *i, bool monthly)
02373 {
02374 StringID str = STR_NULL;
02375 bool closeit = false;
02376 const IndustrySpec *indspec = GetIndustrySpec(i->type);
02377 bool standard = false;
02378 bool suppress_message = false;
02379 bool recalculate_multipliers = false;
02380
02381 bool smooth_economy = indspec->UsesSmoothEconomy();
02382 byte div = 0;
02383 byte mul = 0;
02384 int8 increment = 0;
02385
02386 bool callback_enabled = HasBit(indspec->callback_mask, monthly ? CBM_IND_MONTHLYPROD_CHANGE : CBM_IND_PRODUCTION_CHANGE);
02387 if (callback_enabled) {
02388 uint16 res = GetIndustryCallback(monthly ? CBID_INDUSTRY_MONTHLYPROD_CHANGE : CBID_INDUSTRY_PRODUCTION_CHANGE, 0, Random(), i, i->type, i->location.tile);
02389 if (res != CALLBACK_FAILED) {
02390 suppress_message = HasBit(res, 7);
02391
02392 if (HasBit(res, 8)) str = MapGRFStringID(indspec->grf_prop.grffile->grfid, GB(GetRegister(0x100), 0, 16));
02393 res = GB(res, 0, 4);
02394 switch (res) {
02395 default: NOT_REACHED();
02396 case 0x0: break;
02397 case 0x1: div = 1; break;
02398 case 0x2: mul = 1; break;
02399 case 0x3: closeit = true; break;
02400 case 0x4: standard = true; break;
02401 case 0x5: case 0x6: case 0x7:
02402 case 0x8: div = res - 0x3; break;
02403 case 0x9: case 0xA: case 0xB:
02404 case 0xC: mul = res - 0x7; break;
02405 case 0xD:
02406 case 0xE:
02407 increment = res == 0x0D ? -1 : 1;
02408 break;
02409 case 0xF:
02410 i->prod_level = Clamp(GB(GetRegister(0x100), 16, 8), PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
02411 recalculate_multipliers = true;
02412 break;
02413 }
02414 }
02415 } else {
02416 if (monthly != smooth_economy) return;
02417 if (indspec->life_type == INDUSTRYLIFE_BLACK_HOLE) return;
02418 }
02419
02420 if (standard || (!callback_enabled && (indspec->life_type & (INDUSTRYLIFE_ORGANIC | INDUSTRYLIFE_EXTRACTIVE)) != 0)) {
02421
02422 bool only_decrease = (indspec->behaviour & INDUSTRYBEH_DONT_INCR_PROD) && _settings_game.game_creation.landscape == LT_TEMPERATE;
02423
02424 if (smooth_economy) {
02425 closeit = true;
02426 for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
02427 if (i->produced_cargo[j] == CT_INVALID) continue;
02428 uint32 r = Random();
02429 int old_prod, new_prod, percent;
02430
02431 int mult = (i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_60) ? 1 : -1;
02432
02433 new_prod = old_prod = i->production_rate[j];
02434
02435
02436
02437 if (only_decrease) {
02438 mult = -1;
02439
02440
02441 } else if (Chance16I(1, ((i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_80) ? 6 : 3), r)) {
02442 mult *= -1;
02443 }
02444
02445
02446
02447 if (Chance16I(1, 22, r >> 16)) {
02448 new_prod += mult * (max(((RandomRange(50) + 10) * old_prod) >> 8, 1U));
02449 }
02450
02451
02452 new_prod = Clamp(new_prod, 1, 255);
02453
02454 if (((indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0) && j == 1) {
02455 new_prod = Clamp(new_prod, 0, 16);
02456 }
02457
02458
02459 if (new_prod == old_prod && old_prod > 1) {
02460 closeit = false;
02461 continue;
02462 }
02463
02464 percent = (old_prod == 0) ? 100 : (new_prod * 100 / old_prod - 100);
02465 i->production_rate[j] = new_prod;
02466
02467
02468 if (new_prod > 1) closeit = false;
02469
02470 if (abs(percent) >= 10) {
02471 ReportNewsProductionChangeIndustry(i, i->produced_cargo[j], percent);
02472 }
02473 }
02474 } else {
02475 if (only_decrease || Chance16(1, 3)) {
02476
02477 if (!only_decrease && (i->last_month_pct_transported[0] > PERCENT_TRANSPORTED_60) != Chance16(1, 3)) {
02478 mul = 1;
02479 } else {
02480 div = 1;
02481 }
02482 }
02483 }
02484 }
02485
02486 if (!callback_enabled && (indspec->life_type & INDUSTRYLIFE_PROCESSING)) {
02487 if ( (byte)(_cur_year - i->last_prod_year) >= 5 && Chance16(1, smooth_economy ? 180 : 2)) {
02488 closeit = true;
02489 }
02490 }
02491
02492
02493 while (mul-- != 0 && i->prod_level < PRODLEVEL_MAXIMUM) {
02494 i->prod_level = min(i->prod_level * 2, PRODLEVEL_MAXIMUM);
02495 recalculate_multipliers = true;
02496 if (str == STR_NULL) str = indspec->production_up_text;
02497 }
02498
02499
02500 while (div-- != 0 && !closeit) {
02501 if (i->prod_level == PRODLEVEL_MINIMUM) {
02502 closeit = true;
02503 } else {
02504 i->prod_level = max(i->prod_level / 2, (int)PRODLEVEL_MINIMUM);
02505 recalculate_multipliers = true;
02506 if (str == STR_NULL) str = indspec->production_down_text;
02507 }
02508 }
02509
02510
02511 if (increment != 0) {
02512 if (increment < 0 && i->prod_level == PRODLEVEL_MINIMUM) {
02513 closeit = true;
02514 } else {
02515 i->prod_level = ClampU(i->prod_level + increment, PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
02516 recalculate_multipliers = true;
02517 }
02518 }
02519
02520
02521
02522 if (recalculate_multipliers) i->RecomputeProductionMultipliers();
02523
02524
02525 if (closeit && !CheckIndustryCloseDownProtection(i->type)) {
02526 i->prod_level = PRODLEVEL_CLOSURE;
02527 str = indspec->closure_text;
02528 }
02529
02530 if (!suppress_message && str != STR_NULL) {
02531 NewsSubtype ns;
02532
02533 if (closeit) {
02534 ns = NS_INDUSTRY_CLOSE;
02535 AI::BroadcastNewEvent(new AIEventIndustryClose(i->index));
02536 } else {
02537 switch (WhoCanServiceIndustry(i)) {
02538 case 0: ns = NS_INDUSTRY_NOBODY; break;
02539 case 1: ns = NS_INDUSTRY_OTHER; break;
02540 case 2: ns = NS_INDUSTRY_COMPANY; break;
02541 default: NOT_REACHED();
02542 }
02543 }
02544
02545 if (str > STR_LAST_STRINGID) {
02546 SetDParam(0, STR_TOWN_NAME);
02547 SetDParam(1, i->town->index);
02548 SetDParam(2, indspec->name);
02549 } else if (closeit) {
02550 SetDParam(0, STR_FORMAT_INDUSTRY_NAME);
02551 SetDParam(1, i->town->index);
02552 SetDParam(2, indspec->name);
02553 } else {
02554 SetDParam(0, i->index);
02555 }
02556
02557 AddNewsItem(str,
02558 ns,
02559 closeit ? NR_TILE : NR_INDUSTRY,
02560 closeit ? i->location.tile + TileDiffXY(1, 1) : i->index);
02561 }
02562 }
02563
02571 void IndustryDailyLoop()
02572 {
02573 _economy.industry_daily_change_counter += _economy.industry_daily_increment;
02574
02575
02576
02577
02578 uint16 change_loop = _economy.industry_daily_change_counter >> 16;
02579
02580
02581 _economy.industry_daily_change_counter &= 0xFFFF;
02582
02583 if (change_loop == 0) {
02584 return;
02585 }
02586
02587 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
02588
02589
02590
02591 uint perc = 3;
02592 if ((_industry_builder.wanted_inds >> 16) > GetCurrentTotalNumberOfIndustries()) {
02593 perc = min(9u, perc + (_industry_builder.wanted_inds >> 16) - GetCurrentTotalNumberOfIndustries());
02594 }
02595 for (uint16 j = 0; j < change_loop; j++) {
02596 if (Chance16(perc, 100)) {
02597 _industry_builder.TryBuildNewIndustry();
02598 } else {
02599 Industry *i = Industry::GetRandom();
02600 if (i != NULL) {
02601 ChangeIndustryProduction(i, false);
02602 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
02603 }
02604 }
02605 }
02606
02607 cur_company.Restore();
02608
02609
02610 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 1);
02611 }
02612
02613 void IndustryMonthlyLoop()
02614 {
02615 Backup<CompanyByte> cur_company(_current_company, OWNER_NONE, FILE_LINE);
02616
02617 _industry_builder.MonthlyLoop();
02618
02619 Industry *i;
02620 FOR_ALL_INDUSTRIES(i) {
02621 UpdateIndustryStatistics(i);
02622 if (i->prod_level == PRODLEVEL_CLOSURE) {
02623 delete i;
02624 } else {
02625 ChangeIndustryProduction(i, true);
02626 SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
02627 }
02628 }
02629
02630 cur_company.Restore();
02631
02632
02633 InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 1);
02634 }
02635
02636
02637 void InitializeIndustries()
02638 {
02639 _industry_pool.CleanPool();
02640
02641 Industry::ResetIndustryCounts();
02642 _industry_sound_tile = 0;
02643
02644 _industry_builder.Reset();
02645 }
02646
02647 bool IndustrySpec::IsRawIndustry() const
02648 {
02649
02650 return (this->life_type & (INDUSTRYLIFE_EXTRACTIVE | INDUSTRYLIFE_ORGANIC)) != 0 &&
02651 (this->behaviour & INDUSTRYBEH_CUT_TREES) == 0;
02652 }
02653
02654 Money IndustrySpec::GetConstructionCost() const
02655 {
02656
02657 return (_price[(_settings_game.construction.raw_industry_construction == 1 && this->IsRawIndustry()) ?
02658 PR_BUILD_INDUSTRY_RAW : PR_BUILD_INDUSTRY] * this->cost_multiplier) >> 8;
02659 }
02660
02661 Money IndustrySpec::GetRemovalCost() const
02662 {
02663 return (_price[PR_CLEAR_INDUSTRY] * this->removal_cost_multiplier) >> 8;
02664 }
02665
02666 bool IndustrySpec::UsesSmoothEconomy() const
02667 {
02668 return _settings_game.economy.smooth_economy &&
02669 !(HasBit(this->callback_mask, CBM_IND_PRODUCTION_256_TICKS) || HasBit(this->callback_mask, CBM_IND_PRODUCTION_CARGO_ARRIVAL)) &&
02670 !(HasBit(this->callback_mask, CBM_IND_MONTHLYPROD_CHANGE) || HasBit(this->callback_mask, CBM_IND_PRODUCTION_CHANGE));
02671 }
02672
02673 static CommandCost TerraformTile_Industry(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
02674 {
02675 if (AutoslopeEnabled()) {
02676
02677
02678
02679
02680
02681
02682 Slope tileh_old = GetTileSlope(tile, NULL);
02683
02684 if (!IsSteepSlope(tileh_old) && !IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) {
02685 const IndustryGfx gfx = GetIndustryGfx(tile);
02686 const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
02687
02688
02689 if (HasBit(itspec->callback_mask, CBM_INDT_AUTOSLOPE)) {
02690
02691 uint16 res = GetIndustryTileCallback(CBID_INDTILE_AUTOSLOPE, 0, 0, gfx, Industry::GetByTile(tile), tile);
02692 if ((res == 0) || (res == CALLBACK_FAILED)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02693 } else {
02694
02695 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02696 }
02697 }
02698 }
02699 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02700 }
02701
02702 extern const TileTypeProcs _tile_type_industry_procs = {
02703 DrawTile_Industry,
02704 GetSlopeZ_Industry,
02705 ClearTile_Industry,
02706 AddAcceptedCargo_Industry,
02707 GetTileDesc_Industry,
02708 GetTileTrackStatus_Industry,
02709 ClickTile_Industry,
02710 AnimateTile_Industry,
02711 TileLoop_Industry,
02712 ChangeTileOwner_Industry,
02713 NULL,
02714 NULL,
02715 GetFoundation_Industry,
02716 TerraformTile_Industry,
02717 };