# industry_cmd.cpp

Go to the documentation of this file.

    00001 /* $Id: industry_cmd.cpp 14267 2008-09-07 21:41:47Z rubidium $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "openttd.h"
    00007 #include "clear_map.h"
    00008 #include "industry_map.h"
    00009 #include "station_map.h"
    00010 #include "train.h"
    00011 #include "landscape.h"
    00012 #include "viewport_func.h"
    00013 #include "command_func.h"
    00014 #include "industry.h"
    00015 #include "town.h"
    00016 #include "news.h"
    00017 #include "saveload.h"
    00018 #include "variables.h"
    00019 #include "genworld.h"
    00020 #include "water_map.h"
    00021 #include "tree_map.h"
    00022 #include "cargotype.h"
    00023 #include "newgrf.h"
    00024 #include "newgrf_commons.h"
    00025 #include "newgrf_industries.h"
    00026 #include "newgrf_industrytiles.h"
    00027 #include "newgrf_callbacks.h"
    00028 #include "autoslope.h"
    00029 #include "transparency.h"
    00030 #include "water.h"
    00031 #include "strings_func.h"
    00032 #include "tile_cmd.h"
    00033 #include "functions.h"
    00034 #include "window_func.h"
    00035 #include "date_func.h"
    00036 #include "vehicle_func.h"
    00037 #include "sound_func.h"
    00038
    00039 #include "table/strings.h"
    00040 #include "table/sprites.h"
    00041 #include "table/industry_land.h"
    00042 #include "table/build_industry.h"
    00043
    00044 void ShowIndustryViewWindow(int industry);
    00045 void BuildOilRig(TileIndex tile);
    00046
    00047 static byte _industry_sound_ctr;
    00048 static TileIndex _industry_sound_tile;
    00049
    00050 int _total_industries;                      //general counter
    00051 uint16 _industry_counts[NUM_INDUSTRYTYPES]; // Number of industries per type ingame
    00052
    00053 const Industry **_industry_sort;
    00054 bool _industry_sort_dirty;
    00055
    00056 IndustrySpec _industry_specs[NUM_INDUSTRYTYPES];
    00057 IndustryTileSpec _industry_tile_specs[NUM_INDUSTRYTILES];
    00058
    00063 void ResetIndustries()
    00064 {
    00065   memset(&_industry_specs, 0, sizeof(_industry_specs));
    00066   memcpy(&_industry_specs, &_origin_industry_specs, sizeof(_origin_industry_specs));
    00067
    00068   /* once performed, enable only the current climate industries */
    00069   for (IndustryType i = 0; i < NUM_INDUSTRYTYPES; i++) {
    00070     _industry_specs[i].enabled = i < NEW_INDUSTRYOFFSET &&
    00071         HasBit(_origin_industry_specs[i].climate_availability, _opt.landscape);
    00072   }
    00073
    00074   memset(&_industry_tile_specs, 0, sizeof(_industry_tile_specs));
    00075   memcpy(&_industry_tile_specs, &_origin_industry_tile_specs, sizeof(_origin_industry_tile_specs));
    00076
    00077   /* Reset any overrides that have been set. */
    00078   _industile_mngr.ResetOverride();
    00079   _industry_mngr.ResetOverride();
    00080 }
    00081
    00082 void ResetIndustryCreationProbility(IndustryType type)
    00083 {
    00084   assert(type < INVALID_INDUSTRYTYPE);
    00085   _industry_specs[type].appear_creation[_opt.landscape] = 0;
    00086 }
    00087
    00088 DEFINE_OLD_POOL_GENERIC(Industry, Industry)
    00089
    00090
    00098 IndustryType GetIndustryType(TileIndex tile)
    00099 {
    00100   assert(IsTileType(tile, MP_INDUSTRY));
    00101
    00102   const Industry *ind = GetIndustryByTile(tile);
    00103   return ind->IsValid() ? ind->type : (IndustryType)IT_INVALID;
    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   /* Industry can also be destroyed when not fully initialized.
    00139    * This means that we do not have to clear tiles either. */
    00140   if (this->width == 0) {
    00141     this->xy = 0;
    00142     return;
    00143   }
    00144
    00145   BEGIN_TILE_LOOP(tile_cur, this->width, this->height, this->xy);
    00146     if (IsTileType(tile_cur, MP_INDUSTRY)) {
    00147       if (GetIndustryIndex(tile_cur) == this->index) {
    00148         DoClearSquare(tile_cur);
    00149       }
    00150     } else if (IsTileType(tile_cur, MP_STATION) && IsOilRig(tile_cur)) {
    00151       DeleteOilRig(tile_cur);
    00152     }
    00153   END_TILE_LOOP(tile_cur, this->width, this->height, this->xy);
    00154
    00155   if (GetIndustrySpec(this->type)->behaviour & INDUSTRYBEH_PLANT_FIELDS) {
    00156     /* Remove the farmland and convert it to regular tiles over time. */
    00157     BEGIN_TILE_LOOP(tile_cur, 42, 42, this->xy - TileDiffXY(21, 21)) {
    00158       tile_cur = TILE_MASK(tile_cur);
    00159       if (IsTileType(tile_cur, MP_CLEAR) && IsClearGround(tile_cur, CLEAR_FIELDS) &&
    00160           GetIndustryIndexOfField(tile_cur) == this->index) {
    00161         SetIndustryIndexOfField(tile_cur, INVALID_INDUSTRY);
    00162       }
    00163     } END_TILE_LOOP(tile_cur, 42, 42, this->xy - TileDiff(21, 21))
    00164   }
    00165
    00166   _industry_sort_dirty = true;
    00167   DecIndustryTypeCount(this->type);
    00168
    00169   DeleteSubsidyWithIndustry(this->index);
    00170   DeleteWindowById(WC_INDUSTRY_VIEW, this->index);
    00171   InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0);
    00172   this->xy = 0;
    00173 }
    00174
    00175 static void IndustryDrawSugarMine(const TileInfo *ti)
    00176 {
    00177   const DrawIndustryAnimationStruct *d;
    00178
    00179   if (!IsIndustryCompleted(ti->tile)) return;
    00180
    00181   d = &_draw_industry_spec1[GetIndustryAnimationState(ti->tile)];
    00182
    00183   AddChildSpriteScreen(SPR_IT_SUGAR_MINE_SIEVE + d->image_1, PAL_NONE, d->x, 0);
    00184
    00185   if (d->image_2 != 0) {
    00186     AddChildSpriteScreen(SPR_IT_SUGAR_MINE_CLOUDS + d->image_2 - 1, PAL_NONE, 8, 41);
    00187   }
    00188
    00189   if (d->image_3 != 0) {
    00190     AddChildSpriteScreen(SPR_IT_SUGAR_MINE_PILE + d->image_3 - 1, PAL_NONE,
    00191       _drawtile_proc1[d->image_3 - 1].x, _drawtile_proc1[d->image_3 - 1].y);
    00192   }
    00193 }
    00194
    00195 static void IndustryDrawToffeeQuarry(const TileInfo *ti)
    00196 {
    00197   uint8 x = 0;
    00198
    00199   if (IsIndustryCompleted(ti->tile)) {
    00200     x = _industry_anim_offs_toffee[GetIndustryAnimationState(ti->tile)];
    00201     if (x == 0xFF)
    00202       x = 0;
    00203   }
    00204
    00205   AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_SHOVEL, PAL_NONE, 22 - x, 24 + x);
    00206   AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_TOFFEE, PAL_NONE, 6, 14);
    00207 }
    00208
    00209 static void IndustryDrawBubbleGenerator( const TileInfo *ti)
    00210 {
    00211   if (IsIndustryCompleted(ti->tile)) {
    00212     AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_BUBBLE, PAL_NONE, 5, _industry_anim_offs_bubbles[GetIndustryAnimationState(ti->tile)]);
    00213   } else {
    00214     AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_SPRING, PAL_NONE, 3, 67);
    00215   }
    00216 }
    00217
    00218 static void IndustryDrawToyFactory(const TileInfo *ti)
    00219 {
    00220   const DrawIndustryAnimationStruct *d;
    00221
    00222   d = &_industry_anim_offs_toys[GetIndustryAnimationState(ti->tile)];
    00223
    00224   if (d->image_1 != 0xFF) {
    00225     AddChildSpriteScreen(SPR_IT_TOY_FACTORY_CLAY, PAL_NONE, d->x, 96 + d->image_1);
    00226   }
    00227
    00228   if (d->image_2 != 0xFF) {
    00229     AddChildSpriteScreen(SPR_IT_TOY_FACTORY_ROBOT, PAL_NONE, 16 - d->image_2 * 2, 100 + d->image_2);
    00230   }
    00231
    00232   AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP, PAL_NONE, 7, d->image_3);
    00233   AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP_HOLDER, PAL_NONE, 0, 42);
    00234 }
    00235
    00236 static void IndustryDrawCoalPlantSparks(const TileInfo *ti)
    00237 {
    00238   if (IsIndustryCompleted(ti->tile)) {
    00239     uint8 image = GetIndustryAnimationState(ti->tile);
    00240
    00241     if (image != 0 && image < 7) {
    00242       AddChildSpriteScreen(image + SPR_IT_POWER_PLANT_TRANSFORMERS,
    00243         PAL_NONE,
    00244         _coal_plant_sparks[image - 1].x,
    00245         _coal_plant_sparks[image - 1].y
    00246       );
    00247     }
    00248   }
    00249 }
    00250
    00251 typedef void IndustryDrawTileProc(const TileInfo *ti);
    00252 static IndustryDrawTileProc * const _industry_draw_tile_procs[5] = {
    00253   IndustryDrawSugarMine,
    00254   IndustryDrawToffeeQuarry,
    00255   IndustryDrawBubbleGenerator,
    00256   IndustryDrawToyFactory,
    00257   IndustryDrawCoalPlantSparks,
    00258 };
    00259
    00260 static void DrawTile_Industry(TileInfo *ti)
    00261 {
    00262   IndustryGfx gfx = GetIndustryGfx(ti->tile);
    00263   Industry *ind = GetIndustryByTile(ti->tile);
    00264   const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
    00265   const DrawBuildingsTileStruct *dits;
    00266   SpriteID image;
    00267   SpriteID pal;
    00268
    00269   /* Retrieve pointer to the draw industry tile struct */
    00270   if (gfx >= NEW_INDUSTRYTILEOFFSET) {
    00271     /* Draw the tile using the specialized method of newgrf industrytile.
    00272      * DrawNewIndustry will return false if ever the resolver could not
    00273      * find any sprite to display.  So in this case, we will jump on the
    00274      * substitute gfx instead. */
    00275     if (indts->grf_prop.spritegroup != NULL && DrawNewIndustryTile(ti, ind, gfx, indts)) {
    00276       return;
    00277     } else {
    00278       /* No sprite group (or no valid one) found, meaning no graphics associated.
    00279        * Use the substitute one instead */
    00280       if (indts->grf_prop.subst_id != INVALID_INDUSTRYTILE) {
    00281         gfx = indts->grf_prop.subst_id;
    00282         /* And point the industrytile spec accordingly */
    00283         indts = GetIndustryTileSpec(gfx);
    00284       }
    00285     }
    00286   }
    00287
    00288   dits = &_industry_draw_tile_data[gfx << 2 | (indts->anim_state ?
    00289       GetIndustryAnimationState(ti->tile) & INDUSTRY_COMPLETED :
    00290       GetIndustryConstructionStage(ti->tile))];
    00291
    00292   image = dits->ground.sprite;
    00293   if (HasBit(image, PALETTE_MODIFIER_COLOR) && dits->ground.pal == PAL_NONE) {
    00294     pal = GENERAL_SPRITE_COLOR(ind->random_color);
    00295   } else {
    00296     pal = dits->ground.pal;
    00297   }
    00298
    00299   /* DrawFoundation() modifes ti->z and ti->tileh */
    00300   if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
    00301
    00302   DrawGroundSprite(image, pal);
    00303
    00304   /* Add industry on top of the ground? */
    00305   image = dits->building.sprite;
    00306   if (image != 0) {
    00307     AddSortableSpriteToDraw(image,
    00308       (HasBit(image, PALETTE_MODIFIER_COLOR) && dits->building.pal == PAL_NONE) ? GENERAL_SPRITE_COLOR(ind->random_color) : dits->building.pal,
    00309       ti->x + dits->subtile_x,
    00310       ti->y + dits->subtile_y,
    00311       dits->width,
    00312       dits->height,
    00313       dits->dz,
    00314       ti->z,
    00315       IsTransparencySet(TO_INDUSTRIES));
    00316
    00317     if (IsTransparencySet(TO_INDUSTRIES)) return;
    00318   }
    00319
    00320   {
    00321     int proc = dits->draw_proc - 1;
    00322     if (proc >= 0) _industry_draw_tile_procs[proc](ti);
    00323   }
    00324 }
    00325
    00326 static uint GetSlopeZ_Industry(TileIndex tile, uint x, uint y)
    00327 {
    00328   return GetTileMaxZ(tile);
    00329 }
    00330
    00331 static Foundation GetFoundation_Industry(TileIndex tile, Slope tileh)
    00332 {
    00333   IndustryGfx gfx = GetIndustryGfx(tile);
    00334
    00335   /* For NewGRF industry tiles we might not be drawing a foundation. We need to
    00336    * account for this, as other structures should
    00337    * draw the wall of the foundation in this case.
    00338    */
    00339   if (gfx >= NEW_INDUSTRYTILEOFFSET) {
    00340     const IndustryTileSpec *indts = GetIndustryTileSpec(gfx);
    00341     if (indts->grf_prop.spritegroup != NULL && HasBit(indts->callback_flags, CBM_INDT_DRAW_FOUNDATIONS)) {
    00342       uint32 callback_res = GetIndustryTileCallback(CBID_INDUSTRY_DRAW_FOUNDATIONS, 0, 0, gfx, GetIndustryByTile(tile), tile);
    00343       if (callback_res == 0) return FOUNDATION_NONE;
    00344     }
    00345   }
    00346   return FlatteningFoundation(tileh);
    00347 }
    00348
    00349 static void GetAcceptedCargo_Industry(TileIndex tile, AcceptedCargo ac)
    00350 {
    00351   IndustryGfx gfx = GetIndustryGfx(tile);
    00352   const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
    00353
    00354   /* When we have to use a callback, we put our data in the next two variables */
    00355   CargoID raw_accepts_cargo[lengthof(itspec->accepts_cargo)];
    00356   uint8 raw_acceptance[lengthof(itspec->acceptance)];
    00357
    00358   /* And then these will always point to a same sized array with the required data */
    00359   const CargoID *accepts_cargo = itspec->accepts_cargo;
    00360   const uint8 *acceptance = itspec->acceptance;
    00361
    00362   if (HasBit(itspec->callback_flags, CBM_INDT_ACCEPT_CARGO)) {
    00363     uint16 res = GetIndustryTileCallback(CBID_INDTILE_ACCEPT_CARGO, 0, 0, gfx, GetIndustryByTile(tile), tile);
    00364     if (res != CALLBACK_FAILED) {
    00365       accepts_cargo = raw_accepts_cargo;
    00366       for (uint i = 0; i < lengthof(itspec->accepts_cargo); i++) raw_accepts_cargo[i] = GetCargoTranslation(GB(res, i * 5, 5), itspec->grf_prop.grffile);
    00367     }
    00368   }
    00369
    00370   if (HasBit(itspec->callback_flags, CBM_INDT_CARGO_ACCEPTANCE)) {
    00371     uint16 res = GetIndustryTileCallback(CBID_INDTILE_CARGO_ACCEPTANCE, 0, 0, gfx, GetIndustryByTile(tile), tile);
    00372     if (res != CALLBACK_FAILED) {
    00373       acceptance = raw_acceptance;
    00374       for (uint i = 0; i < lengthof(itspec->accepts_cargo); i++) raw_acceptance[i] = GB(res, i * 4, 4);
    00375     }
    00376   }
    00377
    00378   for (byte i = 0; i < lengthof(itspec->accepts_cargo); i++) {
    00379     CargoID a = accepts_cargo[i];
    00380     /* Only set the value once. */
    00381     if (a != CT_INVALID && ac[a] == 0) ac[a] = acceptance[i];
    00382   }
    00383 }
    00384
    00385 static void GetTileDesc_Industry(TileIndex tile, TileDesc *td)
    00386 {
    00387   const Industry *i = GetIndustryByTile(tile);
    00388
    00389   td->owner = i->owner;
    00390   td->str = GetIndustrySpec(i->type)->name;
    00391   if (!IsIndustryCompleted(tile)) {
    00392     SetDParamX(td->dparam, 0, td->str);
    00393     td->str = STR_2058_UNDER_CONSTRUCTION;
    00394   }
    00395 }
    00396
    00397 static CommandCost ClearTile_Industry(TileIndex tile, byte flags)
    00398 {
    00399   Industry *i = GetIndustryByTile(tile);
    00400   const IndustrySpec *indspec = GetIndustrySpec(i->type);
    00401
    00402   /* water can destroy industries
    00403    * in editor you can bulldoze industries
    00404    * with magic_bulldozer cheat you can destroy industries
    00405    * (area around OILRIG is water, so water shouldn't flood it
    00406    */
    00407   if ((_current_player != OWNER_WATER && _game_mode != GM_EDITOR &&
    00408       !_cheats.magic_bulldozer.value) ||
    00409       ((flags & DC_AUTO) != 0) ||
    00410       (_current_player == OWNER_WATER &&
    00411         ((indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) ||
    00412         HasBit(GetIndustryTileSpec(GetIndustryGfx(tile))->slopes_refused, 5)))) {
    00413     SetDParam(0, indspec->name);
    00414     return_cmd_error(STR_4800_IN_THE_WAY);
    00415   }
    00416
    00417   if (flags & DC_EXEC) delete i;
    00418   return CommandCost(EXPENSES_CONSTRUCTION, indspec->GetRemovalCost());
    00419 }
    00420
    00421 static void TransportIndustryGoods(TileIndex tile)
    00422 {
    00423   Industry *i = GetIndustryByTile(tile);
    00424   const IndustrySpec *indspec = GetIndustrySpec(i->type);
    00425   bool moved_cargo = false;
    00426
    00427   for (uint j = 0; j < lengthof(i->produced_cargo_waiting); j++) {
    00428     uint cw = min(i->produced_cargo_waiting[j], 255);
    00429     if (cw > indspec->minimal_cargo && i->produced_cargo[j] != CT_INVALID) {
    00430       i->produced_cargo_waiting[j] -= cw;
    00431
    00432       /* fluctuating economy? */
    00433       if (_economy.fluct <= 0) cw = (cw + 1) / 2;
    00434
    00435       i->this_month_production[j] += cw;
    00436
    00437       uint am = MoveGoodsToStation(i->xy, i->width, i->height, i->produced_cargo[j], cw);
    00438       i->this_month_transported[j] += am;
    00439
    00440       moved_cargo |= (am != 0);
    00441     }
    00442   }
    00443
    00444   if (moved_cargo && !StartStopIndustryTileAnimation(i, IAT_INDUSTRY_DISTRIBUTES_CARGO)) {
    00445     uint newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_production;
    00446
    00447     if (newgfx != INDUSTRYTILE_NOANIM) {
    00448       ResetIndustryConstructionStage(tile);
    00449       SetIndustryCompleted(tile, true);
    00450       SetIndustryGfx(tile, newgfx);
    00451       MarkTileDirtyByTile(tile);
    00452     }
    00453   }
    00454 }
    00455
    00456
    00457 static void AnimateTile_Industry(TileIndex tile)
    00458 {
    00459   byte m;
    00460   IndustryGfx gfx = GetIndustryGfx(tile);
    00461
    00462   if (GetIndustryTileSpec(gfx)->animation_info != 0xFFFF) {
    00463     AnimateNewIndustryTile(tile);
    00464     return;
    00465   }
    00466
    00467   switch (gfx) {
    00468   case GFX_SUGAR_MINE_SIEVE:
    00469     if ((_tick_counter & 1) == 0) {
    00470       m = GetIndustryAnimationState(tile) + 1;
    00471
    00472       switch (m & 7) {
    00473       case 2: SndPlayTileFx(SND_2D_RIP_2, tile); break;
    00474       case 6: SndPlayTileFx(SND_29_RIP, tile); break;
    00475       }
    00476
    00477       if (m >= 96) {
    00478         m = 0;
    00479         DeleteAnimatedTile(tile);
    00480       }
    00481       SetIndustryAnimationState(tile, m);
    00482
    00483       MarkTileDirtyByTile(tile);
    00484     }
    00485     break;
    00486
    00487   case GFX_TOFFEE_QUARY:
    00488     if ((_tick_counter & 3) == 0) {
    00489       m = GetIndustryAnimationState(tile);
    00490
    00491       if (_industry_anim_offs_toffee[m] == 0xFF) {
    00492         SndPlayTileFx(SND_30_CARTOON_SOUND, tile);
    00493       }
    00494
    00495       if (++m >= 70) {
    00496         m = 0;
    00497         DeleteAnimatedTile(tile);
    00498       }
    00499       SetIndustryAnimationState(tile, m);
    00500
    00501       MarkTileDirtyByTile(tile);
    00502     }
    00503     break;
    00504
    00505   case GFX_BUBBLE_CATCHER:
    00506     if ((_tick_counter & 1) == 0) {
    00507       m = GetIndustryAnimationState(tile);
    00508
    00509       if (++m >= 40) {
    00510         m = 0;
    00511         DeleteAnimatedTile(tile);
    00512       }
    00513       SetIndustryAnimationState(tile, m);
    00514
    00515       MarkTileDirtyByTile(tile);
    00516     }
    00517     break;
    00518
    00519   /* Sparks on a coal plant */
    00520   case GFX_POWERPLANT_SPARKS:
    00521     if ((_tick_counter & 3) == 0) {
    00522       m = GetIndustryAnimationState(tile);
    00523       if (m == 6) {
    00524         SetIndustryAnimationState(tile, 0);
    00525         DeleteAnimatedTile(tile);
    00526       } else {
    00527         SetIndustryAnimationState(tile, m + 1);
    00528         MarkTileDirtyByTile(tile);
    00529       }
    00530     }
    00531     break;
    00532
    00533   case GFX_TOY_FACTORY:
    00534     if ((_tick_counter & 1) == 0) {
    00535       m = GetIndustryAnimationState(tile) + 1;
    00536
    00537       switch (m) {
    00538         case  1: SndPlayTileFx(SND_2C_MACHINERY, tile); break;
    00539         case 23: SndPlayTileFx(SND_2B_COMEDY_HIT, tile); break;
    00540         case 28: SndPlayTileFx(SND_2A_EXTRACT_AND_POP, tile); break;
    00541         default:
    00542           if (m >= 50) {
    00543             int n = GetIndustryAnimationLoop(tile) + 1;
    00544             m = 0;
    00545             if (n >= 8) {
    00546               n = 0;
    00547               DeleteAnimatedTile(tile);
    00548             }
    00549             SetIndustryAnimationLoop(tile, n);
    00550           }
    00551       }
    00552
    00553       SetIndustryAnimationState(tile, m);
    00554       MarkTileDirtyByTile(tile);
    00555     }
    00556     break;
    00557
    00558   case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
    00559   case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
    00560   case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
    00561   case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
    00562     if ((_tick_counter & 3) == 0) {
    00563       IndustryGfx gfx = GetIndustryGfx(tile);
    00564
    00565       gfx = (gfx < 155) ? gfx + 1 : 148;
    00566       SetIndustryGfx(tile, gfx);
    00567       MarkTileDirtyByTile(tile);
    00568     }
    00569     break;
    00570
    00571   case GFX_OILWELL_ANIMATED_1:
    00572   case GFX_OILWELL_ANIMATED_2:
    00573   case GFX_OILWELL_ANIMATED_3:
    00574     if ((_tick_counter & 7) == 0) {
    00575       bool b = Chance16(1, 7);
    00576       IndustryGfx gfx = GetIndustryGfx(tile);
    00577
    00578       m = GetIndustryAnimationState(tile) + 1;
    00579       if (m == 4 && (m = 0, ++gfx) == GFX_OILWELL_ANIMATED_3 + 1 && (gfx = GFX_OILWELL_ANIMATED_1, b)) {
    00580         SetIndustryGfx(tile, GFX_OILWELL_NOT_ANIMATED);
    00581         SetIndustryConstructionStage(tile, 3);
    00582         DeleteAnimatedTile(tile);
    00583       } else {
    00584         SetIndustryAnimationState(tile, m);
    00585         SetIndustryGfx(tile, gfx);
    00586         MarkTileDirtyByTile(tile);
    00587       }
    00588     }
    00589     break;
    00590
    00591   case GFX_COAL_MINE_TOWER_ANIMATED:
    00592   case GFX_COPPER_MINE_TOWER_ANIMATED:
    00593   case GFX_GOLD_MINE_TOWER_ANIMATED: {
    00594       int state = _tick_counter & 0x7FF;
    00595
    00596       if ((state -= 0x400) < 0)
    00597         return;
    00598
    00599       if (state < 0x1A0) {
    00600         if (state < 0x20 || state >= 0x180) {
    00601           m = GetIndustryAnimationState(tile);
    00602           if (!(m & 0x40)) {
    00603             SetIndustryAnimationState(tile, m | 0x40);
    00604             SndPlayTileFx(SND_0B_MINING_MACHINERY, tile);
    00605           }
    00606           if (state & 7)
    00607             return;
    00608         } else {
    00609           if (state & 3)
    00610             return;
    00611         }
    00612         m = (GetIndustryAnimationState(tile) + 1) | 0x40;
    00613         if (m > 0xC2) m = 0xC0;
    00614         SetIndustryAnimationState(tile, m);
    00615         MarkTileDirtyByTile(tile);
    00616       } else if (state >= 0x200 && state < 0x3A0) {
    00617         int i;
    00618         i = (state < 0x220 || state >= 0x380) ? 7 : 3;
    00619         if (state & i)
    00620           return;
    00621
    00622         m = (GetIndustryAnimationState(tile) & 0xBF) - 1;
    00623         if (m < 0x80) m = 0x82;
    00624         SetIndustryAnimationState(tile, m);
    00625         MarkTileDirtyByTile(tile);
    00626       }
    00627     } break;
    00628   }
    00629 }
    00630
    00631 static void CreateIndustryEffectSmoke(TileIndex tile)
    00632 {
    00633   uint x = TileX(tile) * TILE_SIZE;
    00634   uint y = TileY(tile) * TILE_SIZE;
    00635   uint z = GetTileMaxZ(tile);
    00636
    00637   CreateEffectVehicle(x + 15, y + 14, z + 59, EV_CHIMNEY_SMOKE);
    00638 }
    00639
    00640 static void MakeIndustryTileBigger(TileIndex tile)
    00641 {
    00642   byte cnt = GetIndustryConstructionCounter(tile) + 1;
    00643   byte stage;
    00644
    00645   if (cnt != 4) {
    00646     SetIndustryConstructionCounter(tile, cnt);
    00647     return;
    00648   }
    00649
    00650   stage = GetIndustryConstructionStage(tile) + 1;
    00651   SetIndustryConstructionCounter(tile, 0);
    00652   SetIndustryConstructionStage(tile, stage);
    00653   StartStopIndustryTileAnimation(tile, IAT_CONSTRUCTION_STATE_CHANGE);
    00654   if (stage == INDUSTRY_COMPLETED) SetIndustryCompleted(tile, true);
    00655
    00656   MarkTileDirtyByTile(tile);
    00657
    00658   if (!IsIndustryCompleted(tile)) return;
    00659
    00660   IndustryGfx gfx = GetIndustryGfx(tile);
    00661   if (gfx >= NEW_INDUSTRYTILEOFFSET) {
    00662     /* New industries are already animated on construction. */
    00663     return;
    00664   }
    00665
    00666   switch (gfx) {
    00667   case GFX_POWERPLANT_CHIMNEY:
    00668     CreateIndustryEffectSmoke(tile);
    00669     break;
    00670
    00671   case GFX_OILRIG_1:
    00672     if (GetIndustryGfx(tile + TileDiffXY(0, 1)) == GFX_OILRIG_1) BuildOilRig(tile);
    00673     break;
    00674
    00675   case GFX_TOY_FACTORY:
    00676   case GFX_BUBBLE_CATCHER:
    00677   case GFX_TOFFEE_QUARY:
    00678     SetIndustryAnimationState(tile, 0);
    00679     SetIndustryAnimationLoop(tile, 0);
    00680     break;
    00681
    00682   case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2:
    00683   case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4:
    00684   case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6:
    00685   case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8:
    00686     AddAnimatedTile(tile);
    00687     break;
    00688   }
    00689 }
    00690
    00691 static void TileLoopIndustry_BubbleGenerator(TileIndex tile)
    00692 {
    00693   int dir;
    00694   Vehicle *v;
    00695   static const int8 _tileloop_ind_case_161[12] = {
    00696     11,   0, -4, -14,
    00697     -4, -10, -4,   1,
    00698     49,  59, 60,  65,
    00699   };
    00700
    00701   SndPlayTileFx(SND_2E_EXTRACT_AND_POP, tile);
    00702
    00703   dir = Random() & 3;
    00704
    00705   v = CreateEffectVehicleAbove(
    00706     TileX(tile) * TILE_SIZE + _tileloop_ind_case_161[dir + 0],
    00707     TileY(tile) * TILE_SIZE + _tileloop_ind_case_161[dir + 4],
    00708     _tileloop_ind_case_161[dir + 8],
    00709     EV_BUBBLE
    00710   );
    00711
    00712   if (v != NULL) v->u.special.animation_substate = dir;
    00713 }
    00714
    00715 static void TileLoop_Industry(TileIndex tile)
    00716 {
    00717   IndustryGfx newgfx;
    00718   IndustryGfx gfx;
    00719
    00720   TriggerIndustryTile(tile, INDTILE_TRIGGER_TILE_LOOP);
    00721
    00722   if (!IsIndustryCompleted(tile)) {
    00723     MakeIndustryTileBigger(tile);
    00724     return;
    00725   }
    00726
    00727   if (_game_mode == GM_EDITOR) return;
    00728
    00729   TransportIndustryGoods(tile);
    00730
    00731   if (StartStopIndustryTileAnimation(tile, IAT_TILELOOP)) return;
    00732
    00733   newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_next;
    00734   if (newgfx != INDUSTRYTILE_NOANIM) {
    00735     ResetIndustryConstructionStage(tile);
    00736     SetIndustryGfx(tile, newgfx);
    00737     MarkTileDirtyByTile(tile);
    00738     return;
    00739   }
    00740
    00741   gfx = GetIndustryGfx(tile);
    00742
    00743   switch (gfx) {
    00744   case GFX_OILRIG_1: // coast line at oilrigs
    00745   case GFX_OILRIG_2:
    00746   case GFX_OILRIG_3:
    00747   case GFX_OILRIG_4:
    00748   case GFX_OILRIG_5:
    00749     TileLoop_Water(tile);
    00750     break;
    00751
    00752   case GFX_COAL_MINE_TOWER_NOT_ANIMATED:
    00753   case GFX_COPPER_MINE_TOWER_NOT_ANIMATED:
    00754   case GFX_GOLD_MINE_TOWER_NOT_ANIMATED:
    00755     if (!(_tick_counter & 0x400) && Chance16(1, 2)) {
    00756       switch (gfx) {
    00757         case GFX_COAL_MINE_TOWER_NOT_ANIMATED:   gfx = GFX_COAL_MINE_TOWER_ANIMATED;   break;
    00758         case GFX_COPPER_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_ANIMATED; break;
    00759         case GFX_GOLD_MINE_TOWER_NOT_ANIMATED:   gfx = GFX_GOLD_MINE_TOWER_ANIMATED;   break;
    00760       }
    00761       SetIndustryGfx(tile, gfx);
    00762       SetIndustryAnimationState(tile, 0x80);
    00763       AddAnimatedTile(tile);
    00764     }
    00765     break;
    00766
    00767   case GFX_OILWELL_NOT_ANIMATED:
    00768     if (Chance16(1, 6)) {
    00769       SetIndustryGfx(tile, GFX_OILWELL_ANIMATED_1);
    00770       SetIndustryAnimationState(tile, 0);
    00771       AddAnimatedTile(tile);
    00772     }
    00773     break;
    00774
    00775   case GFX_COAL_MINE_TOWER_ANIMATED:
    00776   case GFX_COPPER_MINE_TOWER_ANIMATED:
    00777   case GFX_GOLD_MINE_TOWER_ANIMATED:
    00778     if (!(_tick_counter & 0x400)) {
    00779       switch (gfx) {
    00780         case GFX_COAL_MINE_TOWER_ANIMATED:   gfx = GFX_COAL_MINE_TOWER_NOT_ANIMATED;   break;
    00781         case GFX_COPPER_MINE_TOWER_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_NOT_ANIMATED; break;
    00782         case GFX_GOLD_MINE_TOWER_ANIMATED:   gfx = GFX_GOLD_MINE_TOWER_NOT_ANIMATED;   break;
    00783       }
    00784       SetIndustryGfx(tile, gfx);
    00785       SetIndustryCompleted(tile, true);
    00786       SetIndustryConstructionStage(tile, 3);
    00787       DeleteAnimatedTile(tile);
    00788     }
    00789     break;
    00790
    00791   case GFX_POWERPLANT_SPARKS:
    00792     if (Chance16(1, 3)) {
    00793       SndPlayTileFx(SND_0C_ELECTRIC_SPARK, tile);
    00794       AddAnimatedTile(tile);
    00795     }
    00796     break;
    00797
    00798   case GFX_COPPER_MINE_CHIMNEY:
    00799     CreateEffectVehicleAbove(TileX(tile) * TILE_SIZE + 6, TileY(tile) * TILE_SIZE + 6, 43, EV_SMOKE);
    00800     break;
    00801
    00802
    00803   case GFX_TOY_FACTORY: {
    00804       Industry *i = GetIndustryByTile(tile);
    00805       if (i->was_cargo_delivered) {
    00806         i->was_cargo_delivered = false;
    00807         SetIndustryAnimationLoop(tile, 0);
    00808         AddAnimatedTile(tile);
    00809       }
    00810     }
    00811     break;
    00812
    00813   case GFX_BUBBLE_GENERATOR:
    00814     TileLoopIndustry_BubbleGenerator(tile);
    00815     break;
    00816
    00817   case GFX_TOFFEE_QUARY:
    00818     AddAnimatedTile(tile);
    00819     break;
    00820
    00821   case GFX_SUGAR_MINE_SIEVE:
    00822     if (Chance16(1, 3)) AddAnimatedTile(tile);
    00823     break;
    00824   }
    00825 }
    00826
    00827 static void ClickTile_Industry(TileIndex tile)
    00828 {
    00829   ShowIndustryViewWindow(GetIndustryIndex(tile));
    00830 }
    00831
    00832 static TrackStatus GetTileTrackStatus_Industry(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
    00833 {
    00834   return 0;
    00835 }
    00836
    00837 static void GetProducedCargo_Industry(TileIndex tile, CargoID *b)
    00838 {
    00839   const Industry *i = GetIndustryByTile(tile);
    00840
    00841   b[0] = i->produced_cargo[0];
    00842   b[1] = i->produced_cargo[1];
    00843 }
    00844
    00845 static void ChangeTileOwner_Industry(TileIndex tile, PlayerID old_player, PlayerID new_player)
    00846 {
    00847   /* If the founder merges, the industry was created by the merged company */
    00848   Industry *i = GetIndustryByTile(tile);
    00849   if (i->founder == old_player) i->founder = (new_player == PLAYER_SPECTATOR) ? OWNER_NONE : new_player;
    00850 }
    00851
    00852 static const byte _plantfarmfield_type[] = {1, 1, 1, 1, 1, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6};
    00853
    00854 static bool IsBadFarmFieldTile(TileIndex tile)
    00855 {
    00856   switch (GetTileType(tile)) {
    00857     case MP_CLEAR: return IsClearGround(tile, CLEAR_FIELDS) || IsClearGround(tile, CLEAR_SNOW) || IsClearGround(tile, CLEAR_DESERT);
    00858     case MP_TREES: return (GetTreeGround(tile) == TREE_GROUND_SHORE);
    00859     default:       return true;
    00860   }
    00861 }
    00862
    00863 static bool IsBadFarmFieldTile2(TileIndex tile)
    00864 {
    00865   switch (GetTileType(tile)) {
    00866     case MP_CLEAR: return IsClearGround(tile, CLEAR_SNOW) || IsClearGround(tile, CLEAR_DESERT);
    00867     case MP_TREES: return (GetTreeGround(tile) == TREE_GROUND_SHORE);
    00868     default:       return true;
    00869   }
    00870 }
    00871
    00872 static void SetupFarmFieldFence(TileIndex tile, int size, byte type, Axis direction)
    00873 {
    00874   do {
    00875     tile = TILE_MASK(tile);
    00876
    00877     if (IsTileType(tile, MP_CLEAR) || IsTileType(tile, MP_TREES)) {
    00878       byte or_ = type;
    00879
    00880       if (or_ == 1 && Chance16(1, 7)) or_ = 2;
    00881
    00882       if (direction == AXIS_X) {
    00883         SetFenceSE(tile, or_);
    00884       } else {
    00885         SetFenceSW(tile, or_);
    00886       }
    00887     }
    00888
    00889     tile += (direction == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
    00890   } while (--size);
    00891 }
    00892
    00893 static void PlantFarmField(TileIndex tile, IndustryID industry)
    00894 {
    00895   uint size_x, size_y;
    00896   uint32 r;
    00897   uint count;
    00898   uint counter;
    00899   uint field_type;
    00900   int type;
    00901
    00902   if (_opt.landscape == LT_ARCTIC) {
    00903     if (GetTileZ(tile) + TILE_HEIGHT * 2 >= GetSnowLine())
    00904       return;
    00905   }
    00906
    00907   /* determine field size */
    00908   r = (Random() & 0x303) + 0x404;
    00909   if (_opt.landscape == LT_ARCTIC) r += 0x404;
    00910   size_x = GB(r, 0, 8);
    00911   size_y = GB(r, 8, 8);
    00912
    00913   /* offset tile to match size */
    00914   tile -= TileDiffXY(size_x / 2, size_y / 2);
    00915
    00916   /* check the amount of bad tiles */
    00917   count = 0;
    00918   BEGIN_TILE_LOOP(cur_tile, size_x, size_y, tile)
    00919     cur_tile = TILE_MASK(cur_tile);
    00920     count += IsBadFarmFieldTile(cur_tile);
    00921   END_TILE_LOOP(cur_tile, size_x, size_y, tile)
    00922   if (count * 2 >= size_x * size_y) return;
    00923
    00924   /* determine type of field */
    00925   r = Random();
    00926   counter = GB(r, 5, 3);
    00927   field_type = GB(r, 8, 8) * 9 >> 8;
    00928
    00929   /* make field */
    00930   BEGIN_TILE_LOOP(cur_tile, size_x, size_y, tile)
    00931     cur_tile = TILE_MASK(cur_tile);
    00932     if (!IsBadFarmFieldTile2(cur_tile)) {
    00933       MakeField(cur_tile, field_type, industry);
    00934       SetClearCounter(cur_tile, counter);
    00935       MarkTileDirtyByTile(cur_tile);
    00936     }
    00937   END_TILE_LOOP(cur_tile, size_x, size_y, tile)
    00938
    00939   type = 3;
    00940   if (_opt.landscape != LT_ARCTIC && _opt.landscape != LT_TROPIC) {
    00941     type = _plantfarmfield_type[Random() & 0xF];
    00942   }
    00943
    00944   SetupFarmFieldFence(tile - TileDiffXY(1, 0), size_y, type, AXIS_Y);
    00945   SetupFarmFieldFence(tile - TileDiffXY(0, 1), size_x, type, AXIS_X);
    00946   SetupFarmFieldFence(tile + TileDiffXY(size_x - 1, 0), size_y, type, AXIS_Y);
    00947   SetupFarmFieldFence(tile + TileDiffXY(0, size_y - 1), size_x, type, AXIS_X);
    00948 }
    00949
    00950 void PlantRandomFarmField(const Industry *i)
    00951 {
    00952   int x = i->width  / 2 + Random() % 31 - 16;
    00953   int y = i->height / 2 + Random() % 31 - 16;
    00954
    00955   TileIndex tile = TileAddWrap(i->xy, x, y);
    00956
    00957   if (tile != INVALID_TILE) PlantFarmField(tile, i->index);
    00958 }
    00959
    00966 static bool SearchLumberMillTrees(TileIndex tile, uint32 data)
    00967 {
    00968   if (IsTileType(tile, MP_TREES) && GetTreeGrowth(tile) > 2) {
    00969     PlayerID old_player = _current_player;
    00970     /* found a tree */
    00971
    00972     _current_player = OWNER_NONE;
    00973     _industry_sound_ctr = 1;
    00974     _industry_sound_tile = tile;
    00975     SndPlayTileFx(SND_38_CHAINSAW, tile);
    00976
    00977     DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
    00978
    00979     _current_player = old_player;
    00980     return true;
    00981   }
    00982   return false;
    00983 }
    00984
    00989 static void ChopLumberMillTrees(Industry *i)
    00990 {
    00991   TileIndex tile = i->xy;
    00992
    00993   if (!IsIndustryCompleted(tile)) return;
    00994
    00995   if (CircularTileSearch(tile, 40, SearchLumberMillTrees, 0))
    00996     i->produced_cargo_waiting[0] = min(0xffff, i->produced_cargo_waiting[0] + 45);
    00997 }
    00998
    00999 static void ProduceIndustryGoods(Industry *i)
    01000 {
    01001   uint32 r;
    01002   uint num;
    01003   const IndustrySpec *indsp = GetIndustrySpec(i->type);
    01004
    01005   /* play a sound? */
    01006   if ((i->counter & 0x3F) == 0) {
    01007     if (Chance16R(1, 14, r) && (num = indsp->number_of_sounds) != 0) {
    01008       SndPlayTileFx(
    01009         (SoundFx)(indsp->random_sounds[((r >> 16) * num) >> 16]),
    01010         i->xy);
    01011     }
    01012   }
    01013
    01014   i->counter--;
    01015
    01016   /* produce some cargo */
    01017   if ((i->counter & 0xFF) == 0) {
    01018     if (HasBit(indsp->callback_flags, CBM_IND_PRODUCTION_256_TICKS)) IndustryProductionCallback(i, 1);
    01019
    01020     IndustryBehaviour indbehav = indsp->behaviour;
    01021     i->produced_cargo_waiting[0] = min(0xffff, i->produced_cargo_waiting[0] + i->production_rate[0]);
    01022     i->produced_cargo_waiting[1] = min(0xffff, i->produced_cargo_waiting[1] + i->production_rate[1]);
    01023
    01024     if ((indbehav & INDUSTRYBEH_PLANT_FIELDS) != 0) {
    01025       bool plant;
    01026       if (HasBit(indsp->callback_flags, CBM_IND_SPECIAL_EFFECT)) {
    01027         plant = (GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 0, i, i->type, i->xy) != 0);
    01028       } else {
    01029         plant = Chance16(1, 8);
    01030       }
    01031
    01032       if (plant) PlantRandomFarmField(i);
    01033     }
    01034     if ((indbehav & INDUSTRYBEH_CUT_TREES) != 0) {
    01035       bool cut = ((i->counter & 0x1FF) == 0);
    01036       if (HasBit(indsp->callback_flags, CBM_IND_SPECIAL_EFFECT)) {
    01037         cut = (GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, 0, 1, i, i->type, i->xy) != 0);
    01038       }
    01039
    01040       if (cut) ChopLumberMillTrees(i);
    01041     }
    01042
    01043     TriggerIndustry(i, INDUSTRY_TRIGGER_INDUSTRY_TICK);
    01044     StartStopIndustryTileAnimation(i, IAT_INDUSTRY_TICK);
    01045   }
    01046 }
    01047
    01048 void OnTick_Industry()
    01049 {
    01050   Industry *i;
    01051
    01052   if (_industry_sound_ctr != 0) {
    01053     _industry_sound_ctr++;
    01054
    01055     if (_industry_sound_ctr == 75) {
    01056       SndPlayTileFx(SND_37_BALLOON_SQUEAK, _industry_sound_tile);
    01057     } else if (_industry_sound_ctr == 160) {
    01058       _industry_sound_ctr = 0;
    01059       SndPlayTileFx(SND_36_CARTOON_CRASH, _industry_sound_tile);
    01060     }
    01061   }
    01062
    01063   if (_game_mode == GM_EDITOR) return;
    01064
    01065   FOR_ALL_INDUSTRIES(i) {
    01066     ProduceIndustryGoods(i);
    01067   }
    01068 }
    01069
    01070 static bool CheckNewIndustry_NULL(TileIndex tile)
    01071 {
    01072   return true;
    01073 }
    01074
    01075 static bool CheckNewIndustry_Forest(TileIndex tile)
    01076 {
    01077   if (_opt.landscape == LT_ARCTIC) {
    01078     if (GetTileZ(tile) < HighestSnowLine() + TILE_HEIGHT * 2U) {
    01079       _error_message = STR_4831_FOREST_CAN_ONLY_BE_PLANTED;
    01080       return false;
    01081     }
    01082   }
    01083   return true;
    01084 }
    01085
    01086 static bool CheckNewIndustry_OilRefinery(TileIndex tile)
    01087 {
    01088   if (_game_mode == GM_EDITOR) return true;
    01089   if (DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _patches.oil_refinery_limit) return true;
    01090
    01091   _error_message = STR_483B_CAN_ONLY_BE_POSITIONED;
    01092   return false;
    01093 }
    01094
    01095 extern bool _ignore_restrictions;
    01096
    01097 static bool CheckNewIndustry_OilRig(TileIndex tile)
    01098 {
    01099   if (_game_mode == GM_EDITOR && _ignore_restrictions) return true;
    01100   if (TileHeight(tile) == 0 &&
    01101       DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _patches.oil_refinery_limit) return true;
    01102
    01103   _error_message = STR_483B_CAN_ONLY_BE_POSITIONED;
    01104   return false;
    01105 }
    01106
    01107 static bool CheckNewIndustry_Farm(TileIndex tile)
    01108 {
    01109   if (_opt.landscape == LT_ARCTIC) {
    01110     if (GetTileZ(tile) + TILE_HEIGHT * 2 >= HighestSnowLine()) {
    01111       _error_message = STR_0239_SITE_UNSUITABLE;
    01112       return false;
    01113     }
    01114   }
    01115   return true;
    01116 }
    01117
    01118 static bool CheckNewIndustry_Plantation(TileIndex tile)
    01119 {
    01120   if (GetTropicZone(tile) == TROPICZONE_DESERT) {
    01121     _error_message = STR_0239_SITE_UNSUITABLE;
    01122     return false;
    01123   }
    01124
    01125   return true;
    01126 }
    01127
    01128 static bool CheckNewIndustry_Water(TileIndex tile)
    01129 {
    01130   if (GetTropicZone(tile) != TROPICZONE_DESERT) {
    01131     _error_message = STR_0318_CAN_ONLY_BE_BUILT_IN_DESERT;
    01132     return false;
    01133   }
    01134
    01135   return true;
    01136 }
    01137
    01138 static bool CheckNewIndustry_Lumbermill(TileIndex tile)
    01139 {
    01140   if (GetTropicZone(tile) != TROPICZONE_RAINFOREST) {
    01141     _error_message = STR_0317_CAN_ONLY_BE_BUILT_IN_RAINFOREST;
    01142     return false;
    01143   }
    01144   return true;
    01145 }
    01146
    01147 static bool CheckNewIndustry_BubbleGen(TileIndex tile)
    01148 {
    01149   return GetTileZ(tile) <= TILE_HEIGHT * 4;
    01150 }
    01151
    01152 typedef bool CheckNewIndustryProc(TileIndex tile);
    01153 static CheckNewIndustryProc * const _check_new_industry_procs[CHECK_END] = {
    01154   CheckNewIndustry_NULL,
    01155   CheckNewIndustry_Forest,
    01156   CheckNewIndustry_OilRefinery,
    01157   CheckNewIndustry_Farm,
    01158   CheckNewIndustry_Plantation,
    01159   CheckNewIndustry_Water,
    01160   CheckNewIndustry_Lumbermill,
    01161   CheckNewIndustry_BubbleGen,
    01162   CheckNewIndustry_OilRig
    01163 };
    01164
    01165 static bool CheckSuitableIndustryPos(TileIndex tile)
    01166 {
    01167   uint x = TileX(tile);
    01168   uint y = TileY(tile);
    01169
    01170   if (x < 2 || y < 2 || x > MapMaxX() - 3 || y > MapMaxY() - 3) {
    01171     _error_message = STR_0239_SITE_UNSUITABLE;
    01172     return false;
    01173   }
    01174
    01175   return true;
    01176 }
    01177
    01178 static const Town *CheckMultipleIndustryInTown(TileIndex tile, int type)
    01179 {
    01180   const Town *t;
    01181   const Industry *i;
    01182
    01183   t = ClosestTownFromTile(tile, (uint)-1);
    01184
    01185   if (_patches.multiple_industry_per_town) return t;
    01186
    01187   FOR_ALL_INDUSTRIES(i) {
    01188     if (i->type == (byte)type &&
    01189         i->town == t) {
    01190       _error_message = STR_0287_ONLY_ONE_ALLOWED_PER_TOWN;
    01191       return NULL;
    01192     }
    01193   }
    01194
    01195   return t;
    01196 }
    01197
    01198 bool IsSlopeRefused(Slope current, Slope refused)
    01199 {
    01200   if (IsSteepSlope(current)) return true;
    01201   if (current != SLOPE_FLAT) {
    01202     if (IsSteepSlope(refused)) return true;
    01203
    01204     Slope t = ComplementSlope(current);
    01205
    01206     if (refused & SLOPE_W && (t & SLOPE_NW)) return true;
    01207     if (refused & SLOPE_S && (t & SLOPE_NE)) return true;
    01208     if (refused & SLOPE_E && (t & SLOPE_SW)) return true;
    01209     if (refused & SLOPE_N && (t & SLOPE_SE)) return true;
    01210   }
    01211
    01212   return false;
    01213 }
    01214
    01215 static bool CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTileTable *it, uint itspec_index, int type, bool *custom_shape_check = NULL)
    01216 {
    01217   _error_message = STR_0239_SITE_UNSUITABLE;
    01218   bool refused_slope = false;
    01219   bool custom_shape = false;
    01220
    01221   do {
    01222     IndustryGfx gfx = GetTranslatedIndustryTileID(it->gfx);
    01223     TileIndex cur_tile = tile + ToTileIndexDiff(it->ti);
    01224
    01225     if (!IsValidTile(cur_tile)) {
    01226       if (gfx == GFX_WATERTILE_SPECIALCHECK) continue;
    01227       return false;
    01228     }
    01229
    01230     if (gfx == GFX_WATERTILE_SPECIALCHECK) {
    01231       if (!IsTileType(cur_tile, MP_WATER) ||
    01232           GetTileSlope(cur_tile, NULL) != SLOPE_FLAT) {
    01233         return false;
    01234       }
    01235     } else {
    01236       if (!EnsureNoVehicleOnGround(cur_tile)) return false;
    01237       if (MayHaveBridgeAbove(cur_tile) && IsBridgeAbove(cur_tile)) return false;
    01238
    01239       const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
    01240
    01241       IndustryBehaviour ind_behav = GetIndustrySpec(type)->behaviour;
    01242
    01243       /* Perform land/water check if not disabled */
    01244       if (!HasBit(its->slopes_refused, 5) && (IsWaterTile(cur_tile) == !(ind_behav & INDUSTRYBEH_BUILT_ONWATER))) return false;
    01245
    01246       if (HasBit(its->callback_flags, CBM_INDT_SHAPE_CHECK)) {
    01247         custom_shape = true;
    01248         if (!PerformIndustryTileSlopeCheck(tile, cur_tile, its, type, gfx, itspec_index)) return false;
    01249       } else {
    01250         Slope tileh = GetTileSlope(cur_tile, NULL);
    01251         refused_slope |= IsSlopeRefused(tileh, its->slopes_refused);
    01252       }
    01253
    01254       if (ind_behav & (INDUSTRYBEH_ONLY_INTOWN | INDUSTRYBEH_TOWN1200_MORE)) {
    01255         if (!IsTileType(cur_tile, MP_HOUSE)) {
    01256           _error_message = STR_030D_CAN_ONLY_BE_BUILT_IN_TOWNS;
    01257           return false;
    01258         }
    01259         if (CmdFailed(DoCommand(cur_tile, 0, 0, 0, CMD_LANDSCAPE_CLEAR))) return false;
    01260       } else if ((ind_behav & INDUSTRYBEH_ONLY_NEARTOWN) == 0 || !IsTileType(cur_tile, MP_HOUSE)) {
    01261         if (CmdFailed(DoCommand(cur_tile, 0, 0, DC_AUTO, CMD_LANDSCAPE_CLEAR))) return false;
    01262       }
    01263     }
    01264   } while ((++it)->ti.x != -0x80);
    01265
    01266   if (custom_shape_check != NULL) *custom_shape_check = custom_shape;
    01267
    01268   /* It is almost impossible to have a fully flat land in TG, so what we
    01269    *  do is that we check if we can make the land flat later on. See
    01270    *  CheckIfCanLevelIndustryPlatform(). */
    01271   return !refused_slope || (_patches.land_generator == LG_TERRAGENESIS && _generating_world && !custom_shape && !_ignore_restrictions);
    01272 }
    01273
    01274 static bool CheckIfIndustryIsAllowed(TileIndex tile, int type, const Town *t)
    01275 {
    01276   if ((GetIndustrySpec(type)->behaviour & INDUSTRYBEH_TOWN1200_MORE) && t->population < 1200) {
    01277     _error_message = STR_029D_CAN_ONLY_BE_BUILT_IN_TOWNS;
    01278     return false;
    01279   }
    01280
    01281   if ((GetIndustrySpec(type)->behaviour & INDUSTRYBEH_ONLY_NEARTOWN) && DistanceMax(t->xy, tile) > 9) {
    01282     _error_message = STR_0239_SITE_UNSUITABLE;
    01283     return false;
    01284   }
    01285
    01286   return true;
    01287 }
    01288
    01289 static bool CheckCanTerraformSurroundingTiles(TileIndex tile, uint height, int internal)
    01290 {
    01291   int size_x, size_y;
    01292   uint curh;
    01293
    01294   size_x = 2;
    01295   size_y = 2;
    01296
    01297   /* Check if we don't leave the map */
    01298   if (TileX(tile) == 0 || TileY(tile) == 0 || GetTileType(tile) == MP_VOID) return false;
    01299
    01300   tile += TileDiffXY(-1, -1);
    01301   BEGIN_TILE_LOOP(tile_walk, size_x, size_y, tile) {
    01302     curh = TileHeight(tile_walk);
    01303     /* Is the tile clear? */
    01304     if ((GetTileType(tile_walk) != MP_CLEAR) && (GetTileType(tile_walk) != MP_TREES))
    01305       return false;
    01306
    01307     /* Don't allow too big of a change if this is the sub-tile check */
    01308     if (internal != 0 && Delta(curh, height) > 1) return false;
    01309
    01310     /* Different height, so the surrounding tiles of this tile
    01311      *  has to be correct too (in level, or almost in level)
    01312      *  else you get a chain-reaction of terraforming. */
    01313     if (internal == 0 && curh != height) {
    01314       if (!CheckCanTerraformSurroundingTiles(tile_walk + TileDiffXY(-1, -1), height, internal + 1))
    01315         return false;
    01316     }
    01317   } END_TILE_LOOP(tile_walk, size_x, size_y, tile);
    01318
    01319   return true;
    01320 }
    01321
    01326 static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, uint32 flags, const IndustryTileTable* it, int type)
    01327 {
    01328   const int MKEND = -0x80;   // used for last element in an IndustryTileTable (see build_industry.h)
    01329   int max_x = 0;
    01330   int max_y = 0;
    01331   TileIndex cur_tile;
    01332   uint size_x, size_y;
    01333   uint h, curh;
    01334
    01335   /* Finds dimensions of largest variant of this industry */
    01336   do {
    01337     if (it->gfx == 0xFF) continue;  //  FF been a marquer for a check on clear water, skip it
    01338     if (it->ti.x > max_x) max_x = it->ti.x;
    01339     if (it->ti.y > max_y) max_y = it->ti.y;
    01340   } while ((++it)->ti.x != MKEND);
    01341
    01342   /* Remember level height */
    01343   h = TileHeight(tile);
    01344
    01345   /* Check that all tiles in area and surrounding are clear
    01346    * this determines that there are no obstructing items */
    01347   cur_tile = tile + TileDiffXY(-1, -1);
    01348   size_x = max_x + 4;
    01349   size_y = max_y + 4;
    01350
    01351   /* Check if we don't leave the map */
    01352   if (TileX(cur_tile) == 0 || TileY(cur_tile) == 0 || TileX(cur_tile) + size_x >= MapMaxX() || TileY(cur_tile) + size_y >= MapMaxY()) return false;
    01353
    01354   /* _current_player is OWNER_NONE for randomly generated industries and in editor, or the player who funded or prospected the industry.
    01355    * Perform terraforming as OWNER_TOWN to disable autoslope. */
    01356   PlayerID old_player = _current_player;
    01357   _current_player = OWNER_TOWN;
    01358
    01359   BEGIN_TILE_LOOP(tile_walk, size_x, size_y, cur_tile) {
    01360     curh = TileHeight(tile_walk);
    01361     if (curh != h) {
    01362       /* This tile needs terraforming. Check if we can do that without
    01363        *  damaging the surroundings too much. */
    01364       if (!CheckCanTerraformSurroundingTiles(tile_walk, h, 0)) {
    01365         _current_player = old_player;
    01366         return false;
    01367       }
    01368       /* This is not 100% correct check, but the best we can do without modifying the map.
    01369        *  What is missing, is if the difference in height is more than 1.. */
    01370       if (CmdFailed(DoCommand(tile_walk, SLOPE_N, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND))) {
    01371         _current_player = old_player;
    01372         return false;
    01373       }
    01374     }
    01375   } END_TILE_LOOP(tile_walk, size_x, size_y, cur_tile)
    01376
    01377   if (flags & DC_EXEC) {
    01378     /* Terraform the land under the industry */
    01379     BEGIN_TILE_LOOP(tile_walk, size_x, size_y, cur_tile) {
    01380       curh = TileHeight(tile_walk);
    01381       while (curh != h) {
    01382         /* We give the terraforming for free here, because we can't calculate
    01383          *  exact cost in the test-round, and as we all know, that will cause
    01384          *  a nice assert if they don't match ;) */
    01385         DoCommand(tile_walk, SLOPE_N, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND);
    01386         curh += (curh > h) ? -1 : 1;
    01387       }
    01388     } END_TILE_LOOP(tile_walk, size_x, size_y, cur_tile)
    01389   }
    01390
    01391   _current_player = old_player;
    01392   return true;
    01393 }
    01394
    01395
    01396 static bool CheckIfFarEnoughFromIndustry(TileIndex tile, int type)
    01397 {
    01398   const IndustrySpec *indspec = GetIndustrySpec(type);
    01399   const Industry *i;
    01400
    01401   if (_patches.same_industry_close && indspec->IsRawIndustry())
    01402     /* Allow primary industries to be placed close to any other industry */
    01403     return true;
    01404
    01405   FOR_ALL_INDUSTRIES(i) {
    01406     /* Within 14 tiles from another industry is considered close */
    01407     bool in_low_distance = DistanceMax(tile, i->xy) <= 14;
    01408
    01409     /* check if an industry that accepts the same goods is nearby */
    01410     if (in_low_distance &&
    01411         !indspec->IsRawIndustry() && // not a primary industry?
    01412         indspec->accepts_cargo[0] == i->accepts_cargo[0] && (
    01413         /* at least one of those options must be true */
    01414         _game_mode != GM_EDITOR || // editor must not be stopped
    01415         !_patches.same_industry_close ||
    01416         !_patches.multiple_industry_per_town)) {
    01417       _error_message = STR_INDUSTRY_TOO_CLOSE;
    01418       return false;
    01419     }
    01420
    01421     /* check if there are any conflicting industry types around */
    01422     if ((i->type == indspec->conflicting[0] ||
    01423         i->type == indspec->conflicting[1] ||
    01424         i->type == indspec->conflicting[2]) &&
    01425         in_low_distance) {
    01426       _error_message = STR_INDUSTRY_TOO_CLOSE;
    01427       return false;
    01428     }
    01429   }
    01430   return true;
    01431 }
    01432
    01436 enum ProductionLevels {
    01437   PRODLEVEL_CLOSURE = 0x00,
    01438   PRODLEVEL_MINIMUM = 0x04,
    01439   PRODLEVEL_DEFAULT = 0x10,
    01440   PRODLEVEL_MAXIMUM = 0x80,
    01441 };
    01442
    01443 static void DoCreateNewIndustry(Industry *i, TileIndex tile, int type, const IndustryTileTable *it, byte layout, const Town *t, Owner owner)
    01444 {
    01445   const IndustrySpec *indspec = GetIndustrySpec(type);
    01446   uint32 r;
    01447   uint j;
    01448
    01449   i->xy = tile;
    01450   i->width = i->height = 0;
    01451   i->type = type;
    01452   IncIndustryTypeCount(type);
    01453
    01454   i->produced_cargo[0] = indspec->produced_cargo[0];
    01455   i->produced_cargo[1] = indspec->produced_cargo[1];
    01456   i->accepts_cargo[0] = indspec->accepts_cargo[0];
    01457   i->accepts_cargo[1] = indspec->accepts_cargo[1];
    01458   i->accepts_cargo[2] = indspec->accepts_cargo[2];
    01459   i->production_rate[0] = indspec->production_rate[0];
    01460   i->production_rate[1] = indspec->production_rate[1];
    01461
    01462   /* don't use smooth economy for industries using production related callbacks */
    01463   if (_patches.smooth_economy &&
    01464       !(HasBit(indspec->callback_flags, CBM_IND_PRODUCTION_256_TICKS) || HasBit(indspec->callback_flags, CBM_IND_PRODUCTION_CARGO_ARRIVAL)) && // production callbacks
    01465       !(HasBit(indspec->callback_flags, CBM_IND_MONTHLYPROD_CHANGE) || HasBit(indspec->callback_flags, CBM_IND_PRODUCTION_CHANGE))             // production change callbacks
    01466   ) {
    01467     i->production_rate[0] = min((RandomRange(256) + 128) * i->production_rate[0] >> 8 , 255);
    01468     i->production_rate[1] = min((RandomRange(256) + 128) * i->production_rate[1] >> 8 , 255);
    01469   }
    01470
    01471   i->town = t;
    01472   i->owner = owner;
    01473
    01474   r = Random();
    01475   i->random_color = GB(r, 0, 4);
    01476   i->counter = GB(r, 4, 12);
    01477   i->random = GB(r, 16, 16);
    01478   i->produced_cargo_waiting[0] = 0;
    01479   i->produced_cargo_waiting[1] = 0;
    01480   i->incoming_cargo_waiting[0] = 0;
    01481   i->incoming_cargo_waiting[1] = 0;
    01482   i->incoming_cargo_waiting[2] = 0;
    01483   i->this_month_production[0] = 0;
    01484   i->this_month_production[1] = 0;
    01485   i->this_month_transported[0] = 0;
    01486   i->this_month_transported[1] = 0;
    01487   i->last_month_pct_transported[0] = 0;
    01488   i->last_month_pct_transported[1] = 0;
    01489   i->last_month_transported[0] = 0;
    01490   i->last_month_transported[1] = 0;
    01491   i->was_cargo_delivered = false;
    01492   i->last_prod_year = _cur_year;
    01493   i->last_month_production[0] = i->production_rate[0] * 8;
    01494   i->last_month_production[1] = i->production_rate[1] * 8;
    01495   i->founder = _current_player;
    01496
    01497   if (HasBit(indspec->callback_flags, CBM_IND_DECIDE_COLOUR)) {
    01498     uint16 res = GetIndustryCallback(CBID_INDUSTRY_DECIDE_COLOUR, 0, 0, i, type, INVALID_TILE);
    01499     if (res != CALLBACK_FAILED) i->random_color = GB(res, 0, 4);
    01500   }
    01501
    01502   if (HasBit(indspec->callback_flags, CBM_IND_INPUT_CARGO_TYPES)) {
    01503     for (j = 0; j < lengthof(i->accepts_cargo); j++) i->accepts_cargo[j] = CT_INVALID;
    01504     for (j = 0; j < lengthof(i->accepts_cargo); j++) {
    01505       uint16 res = GetIndustryCallback(CBID_INDUSTRY_INPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE);
    01506       if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
    01507       i->accepts_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
    01508     }
    01509   }
    01510
    01511   if (HasBit(indspec->callback_flags, CBM_IND_OUTPUT_CARGO_TYPES)) {
    01512     for (j = 0; j < lengthof(i->produced_cargo); j++) i->produced_cargo[j] = CT_INVALID;
    01513     for (j = 0; j < lengthof(i->produced_cargo); j++) {
    01514       uint16 res = GetIndustryCallback(CBID_INDUSTRY_OUTPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE);
    01515       if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
    01516       i->produced_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
    01517     }
    01518   }
    01519
    01520   i->construction_date = _date;
    01521   i->construction_type = (_game_mode == GM_EDITOR) ? ICT_SCENARIO_EDITOR :
    01522       (_generating_world ? ICT_MAP_GENERATION : ICT_NORMAL_GAMEPLAY);
    01523
    01524   /* Adding 1 here makes it conform to specs of var44 of varaction2 for industries
    01525    * 0 = created prior of newindustries
    01526    * else, chosen layout + 1 */
    01527   i->selected_layout = layout + 1;
    01528
    01529   if (!_generating_world) i->last_month_production[0] = i->last_month_production[1] = 0;
    01530
    01531   i->prod_level = PRODLEVEL_DEFAULT;
    01532
    01533   do {
    01534     TileIndex cur_tile = tile + ToTileIndexDiff(it->ti);
    01535
    01536     if (it->gfx != GFX_WATERTILE_SPECIALCHECK) {
    01537       byte size;
    01538
    01539       size = it->ti.x;
    01540       if (size > i->width) i->width = size;
    01541       size = it->ti.y;
    01542       if (size > i->height)i->height = size;
    01543
    01544       DoCommand(cur_tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
    01545
    01546       MakeIndustry(cur_tile, i->index, it->gfx, Random());
    01547
    01548       if (_generating_world) {
    01549         SetIndustryConstructionCounter(cur_tile, 3);
    01550         SetIndustryConstructionStage(cur_tile, 2);
    01551       }
    01552
    01553       /* it->gfx is stored in the map. But the translated ID cur_gfx is the interesting one */
    01554       IndustryGfx cur_gfx = GetTranslatedIndustryTileID(it->gfx);
    01555       const IndustryTileSpec *its = GetIndustryTileSpec(cur_gfx);
    01556       if (its->animation_info != 0xFFFF) AddAnimatedTile(cur_tile);
    01557     }
    01558   } while ((++it)->ti.x != -0x80);
    01559
    01560   i->width++;
    01561   i->height++;
    01562
    01563   if (GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_PLANT_ON_BUILT) {
    01564     for (j = 0; j != 50; j++) PlantRandomFarmField(i);
    01565   }
    01566   _industry_sort_dirty = true;
    01567   InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0);
    01568 }
    01569
    01579 static Industry *CreateNewIndustryHelper(TileIndex tile, IndustryType type, uint32 flags, const IndustrySpec *indspec, uint itspec_index, uint32 seed)
    01580 {
    01581   const IndustryTileTable *it = indspec->table[itspec_index];
    01582   bool custom_shape_check = false;
    01583
    01584   if (!CheckIfIndustryTilesAreFree(tile, it, itspec_index, type, &custom_shape_check)) return NULL;
    01585
    01586   if (HasBit(GetIndustrySpec(type)->callback_flags, CBM_IND_LOCATION)) {
    01587     if (!CheckIfCallBackAllowsCreation(tile, type, itspec_index, seed)) return NULL;
    01588   } else {
    01589     if (!_check_new_industry_procs[indspec->check_proc](tile)) return NULL;
    01590   }
    01591
    01592   if (!custom_shape_check && _patches.land_generator == LG_TERRAGENESIS && _generating_world && !_ignore_restrictions && !CheckIfCanLevelIndustryPlatform(tile, 0, it, type)) return NULL;
    01593   if (!CheckIfFarEnoughFromIndustry(tile, type)) return NULL;
    01594
    01595   const Town *t = CheckMultipleIndustryInTown(tile, type);
    01596   if (t == NULL) return NULL;
    01597
    01598   if (!CheckIfIndustryIsAllowed(tile, type, t)) return NULL;
    01599   if (!CheckSuitableIndustryPos(tile)) return NULL;
    01600
    01601   if (!Industry::CanAllocateItem()) return NULL;
    01602
    01603   if (flags & DC_EXEC) {
    01604     Industry *i = new Industry(tile);
    01605     if (!custom_shape_check) CheckIfCanLevelIndustryPlatform(tile, DC_EXEC, it, type);
    01606     DoCreateNewIndustry(i, tile, type, it, itspec_index, t, OWNER_NONE);
    01607
    01608     return i;
    01609   }
    01610
    01611   /* We need to return a non-NULL pointer to tell we have created an industry.
    01612    * However, we haven't created a real one (no DC_EXEC), so return a fake one. */
    01613   return GetIndustry(0);
    01614 }
    01615
    01625 CommandCost CmdBuildIndustry(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    01626 {
    01627   const IndustrySpec *indspec = GetIndustrySpec(GB(p1, 0, 16));
    01628
    01629   /* Check if the to-be built/founded industry is available for this climate. */
    01630   if (!indspec->enabled) {
    01631     return CMD_ERROR;
    01632   }
    01633
    01634   /* If the patch for raw-material industries is not on, you cannot build raw-material industries.
    01635    * Raw material industries are industries that do not accept cargo (at least for now) */
    01636   if (_game_mode != GM_EDITOR && _patches.raw_industry_construction == 0 && indspec->IsRawIndustry()) {
    01637     return CMD_ERROR;
    01638   }
    01639
    01640   if (_game_mode != GM_EDITOR && _patches.raw_industry_construction == 2 && indspec->IsRawIndustry()) {
    01641     if (flags & DC_EXEC) {
    01642       /* Prospecting has a chance to fail, however we cannot guarantee that something can
    01643        * be built on the map, so the chance gets lower when the map is fuller, but there
    01644        * is nothing we can really do about that. */
    01645       if (Random() <= indspec->prospecting_chance) {
    01646         for (int i = 0; i < 5000; i++) {
    01647           /* We should not have more than one Random() in a function call
    01648            * because parameter evaluation order is not guaranteed in the c++ standard
    01649            */
    01650           tile = RandomTile();
    01651           const Industry *ind = CreateNewIndustryHelper(tile, p1, flags, indspec, RandomRange(indspec->num_table), p2);
    01652           if (ind != NULL) {
    01653             SetDParam(0, indspec->name);
    01654             if (indspec->new_industry_text > STR_LAST_STRINGID) {
    01655               SetDParam(1, STR_TOWN);
    01656               SetDParam(2, ind->town->index);
    01657             } else {
    01658               SetDParam(1, ind->town->index);
    01659             }
    01660             AddNewsItem(indspec->new_industry_text,
    01661                 NEWS_FLAGS(NM_THIN, NF_VIEWPORT | NF_TILE, NT_OPENCLOSE, 0), ind->xy, 0);
    01662             break;
    01663           }
    01664         }
    01665       }
    01666     }
    01667   } else {
    01668     int count = indspec->num_table;
    01669     const IndustryTileTable * const *itt = indspec->table;
    01670     int num = Clamp(GB(p1, 16, 16), 0, count - 1);
    01671
    01672     _error_message = STR_0239_SITE_UNSUITABLE;
    01673     do {
    01674       if (--count < 0) return CMD_ERROR;
    01675       if (--num < 0) num = indspec->num_table - 1;
    01676     } while (!CheckIfIndustryTilesAreFree(tile, itt[num], num, p1));
    01677
    01678     if (CreateNewIndustryHelper(tile, p1, flags, indspec, num, p2) == NULL) return CMD_ERROR;
    01679   }
    01680
    01681   return CommandCost(EXPENSES_OTHER, indspec->GetConstructionCost());
    01682 }
    01683
    01684
    01685 Industry *CreateNewIndustry(TileIndex tile, IndustryType type)
    01686 {
    01687   const IndustrySpec *indspec = GetIndustrySpec(type);
    01688
    01689   uint32 seed = Random();
    01690   return CreateNewIndustryHelper(tile, type, DC_EXEC, indspec, RandomRange(indspec->num_table), seed);
    01691 }
    01692
    01693 enum {
    01694   NB_NUMOFINDUSTRY = 11,
    01695   NB_DIFFICULTY_LEVEL = 5,
    01696 };
    01697
    01698 static const byte _numof_industry_table[NB_DIFFICULTY_LEVEL][NB_NUMOFINDUSTRY] = {
    01699   /* difficulty settings for number of industries */
    01700   {0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0},   //none
    01701   {0, 1, 1, 1, 1, 1, 1, 1,  1,  1,  1},   //very low
    01702   {0, 1, 1, 1, 2, 2, 3, 3,  4,  4,  5},   //low
    01703   {0, 1, 2, 3, 4, 5, 6, 7,  8,  9, 10},   //normal
    01704   {0, 2, 3, 4, 6, 7, 8, 9, 10, 10, 10},   //high
    01705 };
    01706
    01711 static void PlaceInitialIndustry(IndustryType type, int amount)
    01712 {
    01713   /* We need to bypass the amount given in parameter if it exceeds the maximum dimension of the
    01714    * _numof_industry_table.  newgrf can specify a big amount */
    01715   int num = (amount > NB_NUMOFINDUSTRY) ? amount : _numof_industry_table[_opt.diff.number_industries][amount];
    01716   const IndustrySpec *ind_spc = GetIndustrySpec(type);
    01717
    01718   /* These are always placed next to the coastline, so we scale by the perimeter instead. */
    01719   num = (ind_spc->check_proc == CHECK_REFINERY || ind_spc->check_proc == CHECK_OIL_RIG) ? ScaleByMapSize1D(num) : ScaleByMapSize(num);
    01720
    01721   if (_opt.diff.number_industries != 0) {
    01722     PlayerID old_player = _current_player;
    01723     _current_player = OWNER_NONE;
    01724     assert(num > 0);
    01725
    01726     do {
    01727       uint i;
    01728
    01729       IncreaseGeneratingWorldProgress(GWP_INDUSTRY);
    01730
    01731       for (i = 0; i < 2000; i++) {
    01732         if (CreateNewIndustry(RandomTile(), type) != NULL) break;
    01733       }
    01734     } while (--num);
    01735
    01736     _current_player = old_player;
    01737   }
    01738 }
    01739
    01742 void GenerateIndustries()
    01743 {
    01744   uint i = 0;
    01745   uint8 chance;
    01746   IndustryType it;
    01747   const IndustrySpec *ind_spc;
    01748
    01749   /* Find the total amount of industries */
    01750   if (_opt.diff.number_industries > 0) {
    01751     for (it = 0; it < NUM_INDUSTRYTYPES; it++) {
    01752
    01753       ind_spc = GetIndustrySpec(it);
    01754
    01755       if (!CheckIfCallBackAllowsAvailability(it, IACT_MAPGENERATION)) {
    01756         ResetIndustryCreationProbility(it);
    01757       }
    01758
    01759       chance = ind_spc->appear_creation[_opt.landscape];
    01760       if (ind_spc->enabled && chance > 0) {
    01761         /* once the chance of appearance is determind, it have to be scaled by
    01762          * the difficulty level. The "chance" in question is more an index into
    01763          * the _numof_industry_table,in fact */
    01764         int num = (chance > NB_NUMOFINDUSTRY) ? chance : _numof_industry_table[_opt.diff.number_industries][chance];
    01765
    01766         /* These are always placed next to the coastline, so we scale by the perimeter instead. */
    01767         num = (ind_spc->check_proc == CHECK_REFINERY || ind_spc->check_proc == CHECK_OIL_RIG) ? ScaleByMapSize1D(num) : ScaleByMapSize(num);
    01768         i += num;
    01769       }
    01770     }
    01771   }
    01772
    01773   SetGeneratingWorldProgress(GWP_INDUSTRY, i);
    01774
    01775   if (_opt.diff.number_industries > 0) {
    01776     for (it = 0; it < NUM_INDUSTRYTYPES; it++) {
    01777       /* Once the number of industries has been determined, let's really create them.
    01778        * The test for chance allows us to try create industries that are available only
    01779        * for this landscape.
    01780        * @todo :  Do we really have to pass chance as un-scaled value, since we've already
    01781        *          processed that scaling above? No, don't think so.  Will find a way. */
    01782       ind_spc = GetIndustrySpec(it);
    01783       if (ind_spc->enabled) {
    01784         chance = ind_spc->appear_creation[_opt.landscape];
    01785         if (chance > 0) PlaceInitialIndustry(it, chance);
    01786       }
    01787     }
    01788   }
    01789 }
    01790
    01791 static void UpdateIndustryStatistics(Industry *i)
    01792 {
    01793   byte pct;
    01794   bool refresh = false;
    01795
    01796   for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
    01797     if (i->produced_cargo[j] != CT_INVALID) {
    01798       pct = 0;
    01799       if (i->this_month_production[j] != 0) {
    01800         i->last_prod_year = _cur_year;
    01801         pct = min(i->this_month_transported[j] * 256 / i->this_month_production[j], 255);
    01802       }
    01803       i->last_month_pct_transported[j] = pct;
    01804
    01805       i->last_month_production[j] = i->this_month_production[j];
    01806       i->this_month_production[j] = 0;
    01807
    01808       i->last_month_transported[j] = i->this_month_transported[j];
    01809       i->this_month_transported[j] = 0;
    01810       refresh = true;
    01811     }
    01812   }
    01813
    01814   if (refresh) InvalidateWindow(WC_INDUSTRY_VIEW, i->index);
    01815 }
    01816
    01818 struct ProbabilityHelper {
    01819   uint16 prob;
    01820   IndustryType ind;
    01821 };
    01822
    01826 static void MaybeNewIndustry(void)
    01827 {
    01828   Industry *ind;               //will receive the industry's creation pointer
    01829   IndustryType rndtype, j;     // Loop controlers
    01830   const IndustrySpec *ind_spc;
    01831   uint num = 0;
    01832   ProbabilityHelper cumulative_probs[NUM_INDUSTRYTYPES]; // probability collector
    01833   uint16 probability_max = 0;
    01834
    01835   /* Generate a list of all possible industries that can be built. */
    01836   for (j = 0; j < NUM_INDUSTRYTYPES; j++) {
    01837     ind_spc = GetIndustrySpec(j);
    01838     byte chance = ind_spc->appear_ingame[_opt.landscape];
    01839
    01840     if (!ind_spc->enabled || chance == 0) continue;
    01841
    01842     /* If there is no Callback CBID_INDUSTRY_AVAILABLE or if this one did anot failed,
    01843      * and if appearing chance for this landscape is above 0, this industry can be chosen */
    01844     if (CheckIfCallBackAllowsAvailability(j, IACT_RANDOMCREATION)) {
    01845       probability_max += chance;
    01846       /* adds the result for this industry */
    01847       cumulative_probs[num].ind = j;
    01848       cumulative_probs[num++].prob = probability_max;
    01849     }
    01850   }
    01851
    01852   /* Find a random type, with maximum being what has been evaluate above*/
    01853   rndtype = RandomRange(probability_max);
    01854   for (j = 0; j < NUM_INDUSTRYTYPES; j++) {
    01855     /* and choose the index of the industry that matches as close as possible this random type */
    01856     if (cumulative_probs[j].prob >= rndtype) break;
    01857   }
    01858
    01859   ind_spc = GetIndustrySpec(cumulative_probs[j].ind);
    01860   /*  Check if it is allowed */
    01861   if ((ind_spc->behaviour & INDUSTRYBEH_BEFORE_1950) && _cur_year > 1950) return;
    01862   if ((ind_spc->behaviour & INDUSTRYBEH_AFTER_1960) && _cur_year < 1960) return;
    01863
    01864   /* try to create 2000 times this industry */
    01865   num = 2000;
    01866   for (;;) {
    01867     ind = CreateNewIndustry(RandomTile(), cumulative_probs[j].ind);
    01868     if (ind != NULL) break;
    01869     if (--num == 0) return;
    01870   }
    01871
    01872   SetDParam(0, ind_spc->name);
    01873   if (ind_spc->new_industry_text > STR_LAST_STRINGID) {
    01874     SetDParam(1, STR_TOWN);
    01875     SetDParam(2, ind->town->index);
    01876   } else {
    01877     SetDParam(1, ind->town->index);
    01878   }
    01879   AddNewsItem(ind_spc->new_industry_text,
    01880     NEWS_FLAGS(NM_THIN, NF_VIEWPORT | NF_TILE, NT_OPENCLOSE, 0), ind->xy, 0);
    01881 }
    01882
    01891 static bool CheckIndustryCloseDownProtection(IndustryType type)
    01892 {
    01893   const IndustrySpec *indspec = GetIndustrySpec(type);
    01894
    01895   /* oil wells (or the industries with that flag set) are always allowed to closedown */
    01896   if (indspec->behaviour & INDUSTRYBEH_DONT_INCR_PROD && _opt.landscape == LT_TEMPERATE) return false;
    01897   return (indspec->behaviour & INDUSTRYBEH_CANCLOSE_LASTINSTANCE) == 0 && GetIndustryTypeCount(type) <= 1;
    01898 }
    01899
    01909 static void CanCargoServiceIndustry(CargoID cargo, Industry *ind, bool *c_accepts, bool *c_produces)
    01910 {
    01911   const IndustrySpec *indspec = GetIndustrySpec(ind->type);
    01912
    01913   /* Check for acceptance of cargo */
    01914   for (byte j = 0; j < lengthof(ind->accepts_cargo); j++) {
    01915     if (ind->accepts_cargo[j] == CT_INVALID) continue;
    01916     if (cargo == ind->accepts_cargo[j]) {
    01917       if (HasBit(indspec->callback_flags, CBM_IND_REFUSE_CARGO)) {
    01918         uint16 res = GetIndustryCallback(CBID_INDUSTRY_REFUSE_CARGO,
    01919             0, GetReverseCargoTranslation(cargo, indspec->grf_prop.grffile),
    01920             ind, ind->type, ind->xy);
    01921         if (res == 0) continue;
    01922       }
    01923       *c_accepts = true;
    01924       break;
    01925     }
    01926   }
    01927
    01928   /* Check for produced cargo */
    01929   for (byte j = 0; j < lengthof(ind->produced_cargo); j++) {
    01930     if (ind->produced_cargo[j] == CT_INVALID) continue;
    01931     if (cargo == ind->produced_cargo[j]) {
    01932       *c_produces = true;
    01933       break;
    01934     }
    01935   }
    01936 }
    01937
    01951 int WhoCanServiceIndustry(Industry* ind)
    01952 {
    01953   /* Find all stations within reach of the industry */
    01954   StationSet stations = FindStationsAroundIndustryTile(ind->xy, ind->width, ind->height);
    01955
    01956   if (stations.size() == 0) return 0; // No stations found at all => nobody services
    01957
    01958   const Vehicle *v;
    01959   int result = 0;
    01960   FOR_ALL_VEHICLES(v) {
    01961     /* Is it worthwhile to try this vehicle? */
    01962     if (v->owner != _local_player && result != 0) continue;
    01963
    01964     /* Check whether it accepts the right kind of cargo */
    01965     bool c_accepts = false;
    01966     bool c_produces = false;
    01967     if (v->type == VEH_TRAIN && IsFrontEngine(v)) {
    01968       const Vehicle *u = v;
    01969       BEGIN_ENUM_WAGONS(u)
    01970         CanCargoServiceIndustry(u->cargo_type, ind, &c_accepts, &c_produces);
    01971       END_ENUM_WAGONS(u)
    01972     } else if (v->type == VEH_ROAD || v->type == VEH_SHIP || v->type == VEH_AIRCRAFT) {
    01973       CanCargoServiceIndustry(v->cargo_type, ind, &c_accepts, &c_produces);
    01974     } else {
    01975       continue;
    01976     }
    01977     if (!c_accepts && !c_produces) continue; // Wrong cargo
    01978
    01979     /* Check orders of the vehicle.
    01980      * We cannot check the first of shared orders only, since the first vehicle in such a chain
    01981      * may have a different cargo type.
    01982      */
    01983     const Order *o;
    01984     FOR_VEHICLE_ORDERS(v, o) {
    01985       if (o->type == OT_GOTO_STATION && !HasBit(o->flags, OF_TRANSFER)) {
    01986         /* Vehicle visits a station to load or unload */
    01987         Station *st = GetStation(o->dest);
    01988         if (!st->IsValid()) continue;
    01989
    01990         /* Same cargo produced by industry is dropped here => not serviced by vehicle v */
    01991         if (HasBit(o->flags, OF_UNLOAD) && !c_accepts) break;
    01992
    01993         if (stations.find(st) != stations.end()) {
    01994           if (v->owner == _local_player) return 2; // Player services industry
    01995           result = 1; // Competitor services industry
    01996         }
    01997       }
    01998     }
    01999   }
    02000   return result;
    02001 }
    02002
    02010 static void ReportNewsProductionChangeIndustry(Industry *ind, CargoID type, int percent)
    02011 {
    02012   NewsType nt;
    02013
    02014   switch (WhoCanServiceIndustry(ind)) {
    02015     case 0: nt = NT_INDUSTRY_NOBODY; break;
    02016     case 1: nt = NT_INDUSTRY_OTHER;  break;
    02017     case 2: nt = NT_INDUSTRY_PLAYER; break;
    02018     default: NOT_REACHED(); break;
    02019   }
    02020   SetDParam(2, abs(percent));
    02021   SetDParam(0, GetCargo(type)->name);
    02022   SetDParam(1, ind->index);
    02023   AddNewsItem(
    02024     percent >= 0 ? STR_INDUSTRY_PROD_GOUP : STR_INDUSTRY_PROD_GODOWN,
    02025     NEWS_FLAGS(NM_THIN, NF_VIEWPORT | NF_TILE, nt, 0),
    02026     ind->xy + TileDiffXY(1, 1), 0
    02027   );
    02028 }
    02029
    02030 enum {
    02031   PERCENT_TRANSPORTED_60 = 153,
    02032   PERCENT_TRANSPORTED_80 = 204,
    02033 };
    02034
    02039 static void ChangeIndustryProduction(Industry *i, bool monthly)
    02040 {
    02041   StringID str = STR_NULL;
    02042   bool closeit = false;
    02043   const IndustrySpec *indspec = GetIndustrySpec(i->type);
    02044   bool standard = true;
    02045   bool suppress_message = false;
    02046   /* don't use smooth economy for industries using production related callbacks */
    02047   bool smooth_economy = _patches.smooth_economy &&
    02048                         !(HasBit(indspec->callback_flags, CBM_IND_PRODUCTION_256_TICKS) || HasBit(indspec->callback_flags, CBM_IND_PRODUCTION_CARGO_ARRIVAL)) && // production callbacks
    02049                         !(HasBit(indspec->callback_flags, CBM_IND_MONTHLYPROD_CHANGE) || HasBit(indspec->callback_flags, CBM_IND_PRODUCTION_CHANGE));            // production change callbacks
    02050   byte div = 0;
    02051   byte mul = 0;
    02052   int8 increment = 0;
    02053
    02054   if (HasBit(indspec->callback_flags, monthly ? CBM_IND_MONTHLYPROD_CHANGE : CBM_IND_PRODUCTION_CHANGE)) {
    02055     uint16 res = GetIndustryCallback(monthly ? CBID_INDUSTRY_MONTHLYPROD_CHANGE : CBID_INDUSTRY_PRODUCTION_CHANGE, 0, Random(), i, i->type, i->xy);
    02056     standard = false;
    02057     monthly = false; // smooth economy is disabled so we need to fake random industry production change to allow 'use standard' result
    02058     if (res != CALLBACK_FAILED) {
    02059       suppress_message = HasBit(res, 7);
    02060       /* Get the custom message if any */
    02061       if (HasBit(res, 8)) str = MapGRFStringID(indspec->grf_prop.grffile->grfid, GB(GetRegister(0x100), 0, 16));
    02062       res = GB(res, 0, 4);
    02063       switch(res) {
    02064         default: NOT_REACHED();
    02065         case 0x0: break;                  // Do nothing, but show the custom message if any
    02066         case 0x1: div = 1; break;         // Halve industry production. If production reaches the quarter of the default, the industry is closed instead.
    02067         case 0x2: mul = 1; break;         // Double industry production if it hasn't reached eight times of the original yet.
    02068         case 0x3: closeit = true; break;  // The industry announces imminent closure, and is physically removed from the map next month.
    02069         case 0x4: standard = true; break; // Do the standard random production change as if this industry was a primary one.
    02070         case 0x5: case 0x6: case 0x7:     // Divide production by 4, 8, 16
    02071         case 0x8: div = res - 0x3; break; // Divide production by 32
    02072         case 0x9: case 0xA: case 0xB:     // Multiply production by 4, 8, 16
    02073         case 0xC: mul = res - 0x7; break; // Multiply production by 32
    02074         case 0xD:                         // decrement production
    02075         case 0xE:                         // increment production
    02076           increment = res == 0x0D ? -1 : 1;
    02077           break;
    02078       }
    02079     }
    02080   }
    02081
    02082   if (standard && monthly != smooth_economy) return;
    02083
    02084   if (standard && indspec->life_type == INDUSTRYLIFE_BLACK_HOLE) return;
    02085
    02086   if (standard && (indspec->life_type & (INDUSTRYLIFE_ORGANIC | INDUSTRYLIFE_EXTRACTIVE)) != 0) {
    02087     /* decrease or increase */
    02088     bool only_decrease = (indspec->behaviour & INDUSTRYBEH_DONT_INCR_PROD) && _opt.landscape == LT_TEMPERATE;
    02089
    02090     if (smooth_economy) {
    02091       closeit = true;
    02092       for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
    02093         if (i->produced_cargo[j] == CT_INVALID) continue;
    02094         uint32 r = Random();
    02095         int old_prod, new_prod, percent;
    02096         /* If over 60% is transported, mult is 1, else mult is -1. */
    02097         int mult = (i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_60) ? 1 : -1;
    02098
    02099         new_prod = old_prod = i->production_rate[j];
    02100
    02101         /* For industries with only_decrease flags (temperate terrain Oil Wells),
    02102          * the multiplier will always be -1 so they will only decrease. */
    02103         if (only_decrease) {
    02104           mult = -1;
    02105         /* For normal industries, if over 60% is transported, 33% chance for decrease.
    02106          * Bonus for very high station ratings (over 80%): 16% chance for decrease. */
    02107         } else if (Chance16I(1, ((i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_80) ? 6 : 3), r)) {
    02108           mult *= -1;
    02109         }
    02110
    02111         /* 4.5% chance for 3-23% (or 1 unit for very low productions) production change,
    02112          * determined by mult value. If mult = 1 prod. increases, else (-1) it decreases. */
    02113         if (Chance16I(1, 22, r >> 16)) {
    02114           new_prod += mult * (max(((RandomRange(50) + 10) * old_prod) >> 8, 1U));
    02115         }
    02116
    02117         /* Prevent production to overflow or Oil Rig passengers to be over-"produced" */
    02118         new_prod = Clamp(new_prod, 1, 255);
    02119
    02120         if (((indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0) && j == 1)
    02121           new_prod = Clamp(new_prod, 0, 16);
    02122
    02123         /* Do not stop closing the industry when it has the lowest possible production rate */
    02124         if (new_prod == old_prod && old_prod > 1) {
    02125           closeit = false;
    02126           continue;
    02127         }
    02128
    02129         percent = (old_prod == 0) ? 100 : (new_prod * 100 / old_prod - 100);
    02130         i->production_rate[j] = new_prod;
    02131
    02132         /* Close the industry when it has the lowest possible production rate */
    02133         if (new_prod > 1) closeit = false;
    02134
    02135         if (abs(percent) >= 10) {
    02136           ReportNewsProductionChangeIndustry(i, i->produced_cargo[j], percent);
    02137         }
    02138       }
    02139     } else {
    02140       if (only_decrease || Chance16(1, 3)) {
    02141         /* If more than 60% transported, 66% chance of increase, else 33% chance of increase */
    02142         if (!only_decrease && (i->last_month_pct_transported[0] > PERCENT_TRANSPORTED_60) != Chance16(1, 3)) {
    02143           mul = 1; // Increase production
    02144         } else {
    02145           div = 1; // Decrease production
    02146         }
    02147       }
    02148     }
    02149   }
    02150
    02151   if (standard && indspec->life_type & INDUSTRYLIFE_PROCESSING) {
    02152     if ( (byte)(_cur_year - i->last_prod_year) >= 5 && Chance16(1, smooth_economy ? 180 : 2)) {
    02153       closeit = true;
    02154     }
    02155   }
    02156
    02157   /* Increase if needed */
    02158   while (mul-- != 0 && i->prod_level < PRODLEVEL_MAXIMUM) {
    02159     i->prod_level = min(i->prod_level * 2, PRODLEVEL_MAXIMUM);
    02160     i->production_rate[0] = min(i->production_rate[0] * 2, 0xFF);
    02161     i->production_rate[1] = min(i->production_rate[1] * 2, 0xFF);
    02162     if (str == STR_NULL) str = indspec->production_up_text;
    02163   }
    02164
    02165   /* Decrease if needed */
    02166   while (div-- != 0 && !closeit) {
    02167     if (i->prod_level == PRODLEVEL_MINIMUM) {
    02168       closeit = true;
    02169     } else {
    02170       i->prod_level = max(i->prod_level / 2, (int)PRODLEVEL_MINIMUM); // typecast to int required to please MSVC
    02171       i->production_rate[0] = (i->production_rate[0] + 1) / 2;
    02172       i->production_rate[1] = (i->production_rate[1] + 1) / 2;
    02173       if (str == STR_NULL) str = indspec->production_down_text;
    02174     }
    02175   }
    02176
    02177   /* Increase or Decreasing the production level if needed */
    02178   if (increment != 0) {
    02179     if (increment < 0 && i->prod_level == PRODLEVEL_MINIMUM) {
    02180       closeit = true;
    02181     } else {
    02182       i->prod_level = ClampU(i->prod_level + increment, PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
    02183     }
    02184   }
    02185
    02186   /* Close if needed and allowed */
    02187   if (closeit && !CheckIndustryCloseDownProtection(i->type)) {
    02188     i->prod_level = PRODLEVEL_CLOSURE;
    02189     str = indspec->closure_text;
    02190   }
    02191
    02192   if (!suppress_message && str != STR_NULL) {
    02193     NewsType nt;
    02194     /* Compute news category */
    02195     if (closeit) {
    02196       nt = NT_OPENCLOSE;
    02197     } else {
    02198       switch (WhoCanServiceIndustry(i)) {
    02199         case 0: nt = NT_INDUSTRY_NOBODY; break;
    02200         case 1: nt = NT_INDUSTRY_OTHER;  break;
    02201         case 2: nt = NT_INDUSTRY_PLAYER; break;
    02202         default: NOT_REACHED(); break;
    02203       }
    02204     }
    02205     /* Set parameters of news string */
    02206     if (str > STR_LAST_STRINGID) {
    02207       SetDParam(0, STR_TOWN);
    02208       SetDParam(1, i->town->index);
    02209       SetDParam(2, indspec->name);
    02210     } else if (closeit) {
    02211       SetDParam(0, STR_INDUSTRY_FORMAT);
    02212       SetDParam(1, i->town->index);
    02213       SetDParam(2, indspec->name);
    02214     } else {
    02215       SetDParam(0, i->index);
    02216     }
    02217     /* and report the news to the user */
    02218     AddNewsItem(str,
    02219       NEWS_FLAGS(NM_THIN, NF_VIEWPORT | NF_TILE, nt, 0),
    02220       i->xy + TileDiffXY(1, 1), 0);
    02221   }
    02222 }
    02223
    02224 void IndustryMonthlyLoop()
    02225 {
    02226   Industry *i;
    02227   PlayerID old_player = _current_player;
    02228   _current_player = OWNER_NONE;
    02229
    02230   FOR_ALL_INDUSTRIES(i) {
    02231     UpdateIndustryStatistics(i);
    02232     if (i->prod_level == PRODLEVEL_CLOSURE) {
    02233       delete i;
    02234     } else {
    02235       ChangeIndustryProduction(i, true);
    02236     }
    02237   }
    02238
    02239   /* 3% chance that we start a new industry */
    02240   if (Chance16(3, 100)) {
    02241     MaybeNewIndustry();
    02242   } else {
    02243     i = GetRandomIndustry();
    02244     if (i != NULL) ChangeIndustryProduction(i, false);
    02245   }
    02246
    02247   _current_player = old_player;
    02248
    02249   /* production-change */
    02250   _industry_sort_dirty = true;
    02251   InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0);
    02252 }
    02253
    02254
    02255 void InitializeIndustries()
    02256 {
    02257   _Industry_pool.CleanPool();
    02258   _Industry_pool.AddBlockToPool();
    02259
    02260   ResetIndustryCounts();
    02261   _industry_sort_dirty = true;
    02262   _industry_sound_tile = 0;
    02263 }
    02264
    02265 bool IndustrySpec::IsRawIndustry() const
    02266 {
    02267   /* Lumber mills are extractive/organic, but can always be built like a non-raw industry */
    02268   return (this->life_type & (INDUSTRYLIFE_EXTRACTIVE | INDUSTRYLIFE_ORGANIC)) != 0 &&
    02269       (this->behaviour & INDUSTRYBEH_CUT_TREES) == 0;
    02270 }
    02271
    02272 Money IndustrySpec::GetConstructionCost() const
    02273 {
    02274   return (_price.build_industry *
    02275       (_patches.raw_industry_construction == 1 && this->IsRawIndustry() ?
    02276           this->raw_industry_cost_multiplier :
    02277           this->cost_multiplier
    02278       )) >> 8;
    02279 }
    02280
    02281 Money IndustrySpec::GetRemovalCost() const
    02282 {
    02283   return (_price.remove_house * this->removal_cost_multiplier) >> 8;
    02284 }
    02285
    02286 static CommandCost TerraformTile_Industry(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new)
    02287 {
    02288   if (AutoslopeEnabled()) {
    02289     /* We imitate here TTDP's behaviour:
    02290      *  - Both new and old slope must not be steep.
    02291      *  - TileMaxZ must not be changed.
    02292      *  - Allow autoslope by default.
    02293      *  - Disallow autoslope if callback succeeds and returns non-zero.
    02294      */
    02295     Slope tileh_old = GetTileSlope(tile, NULL);
    02296     /* TileMaxZ must not be changed. Slopes must not be steep. */
    02297     if (!IsSteepSlope(tileh_old) && !IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) {
    02298       const IndustryGfx gfx = GetIndustryGfx(tile);
    02299       const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
    02300
    02301       /* Call callback 3C 'disable autosloping for industry tiles'. */
    02302       if (HasBit(itspec->callback_flags, CBM_INDT_AUTOSLOPE)) {
    02303         /* If the callback fails, allow autoslope. */
    02304         uint16 res = GetIndustryTileCallback(CBID_INDUSTRY_AUTOSLOPE, 0, 0, gfx, GetIndustryByTile(tile), tile);
    02305         if ((res == 0) || (res == CALLBACK_FAILED)) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
    02306       } else {
    02307         /* allow autoslope */
    02308         return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
    02309       }
    02310     }
    02311   }
    02312   return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    02313 }
    02314
    02315 extern const TileTypeProcs _tile_type_industry_procs = {
    02316   DrawTile_Industry,           /* draw_tile_proc */
    02317   GetSlopeZ_Industry,          /* get_slope_z_proc */
    02318   ClearTile_Industry,          /* clear_tile_proc */
    02319   GetAcceptedCargo_Industry,   /* get_accepted_cargo_proc */
    02320   GetTileDesc_Industry,        /* get_tile_desc_proc */
    02321   GetTileTrackStatus_Industry, /* get_tile_track_status_proc */
    02322   ClickTile_Industry,          /* click_tile_proc */
    02323   AnimateTile_Industry,        /* animate_tile_proc */
    02324   TileLoop_Industry,           /* tile_loop_proc */
    02325   ChangeTileOwner_Industry,    /* change_tile_owner_proc */
    02326   GetProducedCargo_Industry,   /* get_produced_cargo_proc */
    02327   NULL,                        /* vehicle_enter_tile_proc */
    02328   GetFoundation_Industry,      /* get_foundation_proc */
    02329   TerraformTile_Industry,      /* terraform_tile_proc */
    02330 };
    02331
    02332 static const SaveLoad _industry_desc[] = {
    02333   SLE_CONDVAR(Industry, xy,                         SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
    02334   SLE_CONDVAR(Industry, xy,                         SLE_UINT32,                  6, SL_MAX_VERSION),
    02335       SLE_VAR(Industry, width,                      SLE_UINT8),
    02336       SLE_VAR(Industry, height,                     SLE_UINT8),
    02337       SLE_REF(Industry, town,                       REF_TOWN),
    02338   SLE_CONDNULL( 2, 0, 60),
    02339   SLE_CONDARR(Industry, produced_cargo,             SLE_UINT8,  2,              78, SL_MAX_VERSION),
    02340   SLE_CONDARR(Industry, incoming_cargo_waiting,     SLE_UINT16, 3,              70, SL_MAX_VERSION),
    02341       SLE_ARR(Industry, produced_cargo_waiting,     SLE_UINT16, 2),
    02342       SLE_ARR(Industry, production_rate,            SLE_UINT8,  2),
    02343   SLE_CONDNULL( 3, 0, 60),
    02344   SLE_CONDARR(Industry, accepts_cargo,              SLE_UINT8,  3,              78, SL_MAX_VERSION),
    02345       SLE_VAR(Industry, prod_level,                 SLE_UINT8),
    02346       SLE_ARR(Industry, this_month_production,      SLE_UINT16, 2),
    02347       SLE_ARR(Industry, this_month_transported,     SLE_UINT16, 2),
    02348       SLE_ARR(Industry, last_month_pct_transported, SLE_UINT8,  2),
    02349       SLE_ARR(Industry, last_month_production,      SLE_UINT16, 2),
    02350       SLE_ARR(Industry, last_month_transported,     SLE_UINT16, 2),
    02351
    02352       SLE_VAR(Industry, counter,                    SLE_UINT16),
    02353
    02354       SLE_VAR(Industry, type,                       SLE_UINT8),
    02355       SLE_VAR(Industry, owner,                      SLE_UINT8),
    02356       SLE_VAR(Industry, random_color,               SLE_UINT8),
    02357   SLE_CONDVAR(Industry, last_prod_year,             SLE_FILE_U8 | SLE_VAR_I32,  0, 30),
    02358   SLE_CONDVAR(Industry, last_prod_year,             SLE_INT32,                 31, SL_MAX_VERSION),
    02359       SLE_VAR(Industry, was_cargo_delivered,        SLE_UINT8),
    02360
    02361   SLE_CONDVAR(Industry, founder,                    SLE_UINT8,                 70, SL_MAX_VERSION),
    02362   SLE_CONDVAR(Industry, construction_date,          SLE_INT32,                 70, SL_MAX_VERSION),
    02363   SLE_CONDVAR(Industry, construction_type,          SLE_UINT8,                 70, SL_MAX_VERSION),
    02364   SLE_CONDVAR(Industry, last_cargo_accepted_at,     SLE_INT32,                 70, SL_MAX_VERSION),
    02365   SLE_CONDVAR(Industry, selected_layout,            SLE_UINT8,                 73, SL_MAX_VERSION),
    02366
    02367   SLE_CONDARRX(cpp_offsetof(Industry, psa) + cpp_offsetof(Industry::PersistentStorage, storage), SLE_UINT32, 16, 76, SL_MAX_VERSION),
    02368
    02369   SLE_CONDVAR(Industry, random_triggers,            SLE_UINT8,                 82, SL_MAX_VERSION),
    02370   SLE_CONDVAR(Industry, random,                     SLE_UINT16,                82, SL_MAX_VERSION),
    02371
    02372   /* reserve extra space in savegame here. (currently 32 bytes) */
    02373   SLE_CONDNULL(32, 2, SL_MAX_VERSION),
    02374
    02375   SLE_END()
    02376 };
    02377
    02378 static void Save_INDY()
    02379 {
    02380   Industry *ind;
    02381
    02382   /* Write the industries */
    02383   FOR_ALL_INDUSTRIES(ind) {
    02384     SlSetArrayIndex(ind->index);
    02385     SlObject(ind, _industry_desc);
    02386   }
    02387 }
    02388
    02389 /* Save and load the mapping between the industry/tile id on the map, and the grf file
    02390  * it came from. */
    02391 static const SaveLoad _industries_id_mapping_desc[] = {
    02392   SLE_VAR(EntityIDMapping, grfid,         SLE_UINT32),
    02393   SLE_VAR(EntityIDMapping, entity_id,     SLE_UINT8),
    02394   SLE_VAR(EntityIDMapping, substitute_id, SLE_UINT8),
    02395   SLE_END()
    02396 };
    02397
    02398 static void Save_IIDS()
    02399 {
    02400   uint i;
    02401   uint j = _industry_mngr.GetMaxMapping();
    02402
    02403   for (i = 0; i < j; i++) {
    02404     SlSetArrayIndex(i);
    02405     SlObject(&_industry_mngr.mapping_ID[i], _industries_id_mapping_desc);
    02406   }
    02407 }
    02408
    02409 static void Save_TIDS()
    02410 {
    02411   uint i;
    02412   uint j = _industile_mngr.GetMaxMapping();
    02413
    02414   for (i = 0; i < j; i++) {
    02415     SlSetArrayIndex(i);
    02416     SlObject(&_industile_mngr.mapping_ID[i], _industries_id_mapping_desc);
    02417   }
    02418 }
    02419
    02420 static void Load_INDY()
    02421 {
    02422   int index;
    02423
    02424   ResetIndustryCounts();
    02425
    02426   while ((index = SlIterateArray()) != -1) {
    02427     Industry *i = new (index) Industry();
    02428     SlObject(i, _industry_desc);
    02429     IncIndustryTypeCount(i->type);
    02430   }
    02431 }
    02432
    02433 static void Load_IIDS()
    02434 {
    02435   int index;
    02436   uint max_id;
    02437
    02438   /* clear the current mapping stored.
    02439    * This will create the manager if ever it is not yet done */
    02440   _industry_mngr.ResetMapping();
    02441
    02442   /* get boundary for the temporary map loader NUM_INDUSTRYTYPES? */
    02443   max_id = _industry_mngr.GetMaxMapping();
    02444
    02445   while ((index = SlIterateArray()) != -1) {
    02446     if ((uint)index >= max_id) break;
    02447     SlObject(&_industry_mngr.mapping_ID[index], _industries_id_mapping_desc);
    02448   }
    02449 }
    02450
    02451 static void Load_TIDS()
    02452 {
    02453   int index;
    02454   uint max_id;
    02455
    02456   /* clear the current mapping stored.
    02457    * This will create the manager if ever it is not yet done */
    02458   _industile_mngr.ResetMapping();
    02459
    02460   /* get boundary for the temporary map loader NUM_INDUSTILES? */
    02461   max_id = _industile_mngr.GetMaxMapping();
    02462
    02463   while ((index = SlIterateArray()) != -1) {
    02464     if ((uint)index >= max_id) break;
    02465     SlObject(&_industile_mngr.mapping_ID[index], _industries_id_mapping_desc);
    02466   }
    02467 }
    02468
    02469 extern const ChunkHandler _industry_chunk_handlers[] = {
    02470   { 'INDY', Save_INDY, Load_INDY, CH_ARRAY},
    02471   { 'IIDS', Save_IIDS, Load_IIDS, CH_ARRAY},
    02472   { 'TIDS', Save_TIDS, Load_TIDS, CH_ARRAY | CH_LAST},
    02473 };