industry_cmd.cpp

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

Generated on Wed Oct 1 17:03:21 2008 for openttd by  doxygen 1.5.6