industry_cmd.cpp

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

Generated on Thu Jan 20 22:57:34 2011 for OpenTTD by  doxygen 1.6.1