tron@2186: /* $Id$ */ tron@2186: truelight@0: #include "stdafx.h" Darkvater@1891: #include "openttd.h" tron@507: #include "table/strings.h" celestar@2148: #include "table/sprites.h" tron@2163: #include "functions.h" tron@679: #include "map.h" tron@1209: #include "tile.h" truelight@0: #include "viewport.h" truelight@0: #include "command.h" truelight@0: #include "industry.h" truelight@0: #include "town.h" truelight@0: #include "vehicle.h" truelight@0: #include "news.h" truelight@0: #include "saveload.h" truelight@0: #include "economy.h" tron@337: #include "sound.h" tron@2159: #include "variables.h" truelight@0: truelight@1267: enum { truelight@1267: /* Max industries: 64000 (8 * 8000) */ truelight@1267: INDUSTRY_POOL_BLOCK_SIZE_BITS = 3, /* In bits, so (1 << 3) == 8 */ truelight@1267: INDUSTRY_POOL_MAX_BLOCKS = 8000, truelight@1267: }; truelight@1267: truelight@1267: /** truelight@1267: * Called if a new block is added to the industry-pool truelight@1267: */ tron@2817: static void IndustryPoolNewBlock(uint start_item) truelight@1267: { truelight@1267: Industry *i; truelight@1267: tron@2639: FOR_ALL_INDUSTRIES_FROM(i, start_item) i->index = start_item++; truelight@1267: } truelight@1267: truelight@1267: /* Initialize the industry-pool */ truelight@1267: MemoryPool _industry_pool = { "Industry", INDUSTRY_POOL_MAX_BLOCKS, INDUSTRY_POOL_BLOCK_SIZE_BITS, sizeof(Industry), &IndustryPoolNewBlock, 0, 0, NULL }; truelight@1267: tron@2630: static byte _industry_sound_ctr; tron@2630: static TileIndex _industry_sound_tile; truelight@0: truelight@0: void ShowIndustryViewWindow(int industry); tron@1977: void BuildOilRig(TileIndex tile); tron@1977: void DeleteOilRig(TileIndex tile); truelight@0: truelight@0: typedef struct DrawIndustryTileStruct { truelight@0: uint32 sprite_1; truelight@0: uint32 sprite_2; truelight@0: tron@2653: byte subtile_x:4; tron@2653: byte subtile_y:4; tron@2653: byte width:4; tron@2653: byte height:4; truelight@0: byte dz; truelight@0: byte proc; truelight@0: } DrawIndustryTileStruct; truelight@0: truelight@0: truelight@0: typedef struct DrawIndustrySpec1Struct { truelight@0: byte x; truelight@0: byte image_1; truelight@0: byte image_2; truelight@0: byte image_3; truelight@0: } DrawIndustrySpec1Struct; truelight@0: truelight@0: typedef struct DrawIndustrySpec4Struct { truelight@0: byte image_1; truelight@0: byte image_2; truelight@0: byte image_3; truelight@0: } DrawIndustrySpec4Struct; truelight@0: truelight@0: typedef struct IndustryTileTable { tron@909: TileIndexDiffC ti; truelight@0: byte map5; truelight@0: } IndustryTileTable; truelight@0: truelight@0: typedef struct IndustrySpec { Darkvater@1786: const IndustryTileTable *const *table; truelight@0: byte num_table; truelight@0: byte a,b,c; truelight@0: byte produced_cargo[2]; truelight@0: byte production_rate[2]; truelight@0: byte accepts_cargo[3]; truelight@0: byte check_proc; truelight@0: } IndustrySpec; truelight@0: Darkvater@1786: #include "table/industry_land.h" truelight@0: #include "table/build_industry.h" truelight@0: truelight@1320: typedef enum IndustryType { truelight@1320: INDUSTRY_NOT_CLOSABLE, //! Industry can never close truelight@1320: INDUSTRY_PRODUCTION, //! Industry can close and change of production truelight@1320: INDUSTRY_CLOSABLE, //! Industry can only close (no production change) truelight@1320: } IndustryType; truelight@1320: truelight@1320: truelight@1320: static const IndustryType _industry_close_mode[37] = { truelight@1320: /* COAL_MINE */ INDUSTRY_PRODUCTION, truelight@1320: /* POWER_STATION */ INDUSTRY_NOT_CLOSABLE, truelight@1320: /* SAWMILL */ INDUSTRY_CLOSABLE, truelight@1320: /* FOREST */ INDUSTRY_PRODUCTION, truelight@1320: /* OIL_REFINERY */ INDUSTRY_CLOSABLE, truelight@1320: /* OIL_RIG */ INDUSTRY_PRODUCTION, truelight@1320: /* FACTORY */ INDUSTRY_CLOSABLE, truelight@1320: /* PRINTING_WORKS */ INDUSTRY_CLOSABLE, truelight@1320: /* STEEL_MILL */ INDUSTRY_CLOSABLE, truelight@1320: /* FARM */ INDUSTRY_PRODUCTION, truelight@1320: /* COPPER_MINE */ INDUSTRY_PRODUCTION, truelight@1320: /* OIL_WELL */ INDUSTRY_PRODUCTION, truelight@1320: /* BANK */ INDUSTRY_NOT_CLOSABLE, truelight@1320: /* FOOD_PROCESS */ INDUSTRY_CLOSABLE, truelight@1320: /* PAPER_MILL */ INDUSTRY_CLOSABLE, truelight@1320: /* GOLD_MINE */ INDUSTRY_PRODUCTION, truelight@1320: /* BANK_2, */ INDUSTRY_NOT_CLOSABLE, truelight@1320: /* DIAMOND_MINE */ INDUSTRY_PRODUCTION, truelight@1320: /* IRON_MINE */ INDUSTRY_PRODUCTION, truelight@1320: /* FRUIT_PLANTATION */ INDUSTRY_PRODUCTION, truelight@1320: /* RUBBER_PLANTATION */ INDUSTRY_PRODUCTION, truelight@1320: /* WATER_SUPPLY */ INDUSTRY_PRODUCTION, truelight@1320: /* WATER_TOWER */ INDUSTRY_NOT_CLOSABLE, truelight@1320: /* FACTORY_2 */ INDUSTRY_CLOSABLE, truelight@1320: /* FARM_2 */ INDUSTRY_PRODUCTION, truelight@1320: /* LUMBER_MILL */ INDUSTRY_CLOSABLE, truelight@1320: /* COTTON_CANDY */ INDUSTRY_PRODUCTION, truelight@1320: /* CANDY_FACTORY */ INDUSTRY_CLOSABLE, truelight@1320: /* BATTERY_FARM */ INDUSTRY_PRODUCTION, truelight@1320: /* COLA_WELLS */ INDUSTRY_PRODUCTION, truelight@1320: /* TOY_SHOP */ INDUSTRY_NOT_CLOSABLE, truelight@1320: /* TOY_FACTORY */ INDUSTRY_CLOSABLE, truelight@1320: /* PLASTIC_FOUNTAINS */ INDUSTRY_PRODUCTION, truelight@1320: /* FIZZY_DRINK_FACTORY */INDUSTRY_CLOSABLE, truelight@1320: /* BUBBLE_GENERATOR */ INDUSTRY_PRODUCTION, truelight@1320: /* TOFFEE_QUARRY */ INDUSTRY_PRODUCTION, truelight@1320: /* SUGAR_MINE */ INDUSTRY_PRODUCTION truelight@0: }; truelight@0: truelight@0: static const StringID _industry_prod_up_strings[] = { truelight@0: STR_4836_NEW_COAL_SEAM_FOUND_AT, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4837_NEW_OIL_RESERVES_FOUND, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4838_IMPROVED_FARMING_METHODS, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4837_NEW_OIL_RESERVES_FOUND, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4838_IMPROVED_FARMING_METHODS, truelight@0: STR_4838_IMPROVED_FARMING_METHODS, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4838_IMPROVED_FARMING_METHODS, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4838_IMPROVED_FARMING_METHODS, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4838_IMPROVED_FARMING_METHODS, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: STR_4835_INCREASES_PRODUCTION, truelight@0: }; truelight@0: truelight@0: static const StringID _industry_prod_down_strings[] = { truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_483A_INSECT_INFESTATION_CAUSES, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_483A_INSECT_INFESTATION_CAUSES, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_483A_INSECT_INFESTATION_CAUSES, truelight@0: STR_483A_INSECT_INFESTATION_CAUSES, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_483A_INSECT_INFESTATION_CAUSES, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_483A_INSECT_INFESTATION_CAUSES, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: STR_4839_PRODUCTION_DOWN_BY_50, truelight@0: }; truelight@0: truelight@0: static const StringID _industry_close_strings[] = { truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, truelight@0: STR_4833_SUPPLY_PROBLEMS_CAUSE_TO, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, truelight@0: STR_4833_SUPPLY_PROBLEMS_CAUSE_TO, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, truelight@0: STR_4833_SUPPLY_PROBLEMS_CAUSE_TO, truelight@0: STR_4833_SUPPLY_PROBLEMS_CAUSE_TO, truelight@0: STR_4833_SUPPLY_PROBLEMS_CAUSE_TO, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, truelight@0: STR_4833_SUPPLY_PROBLEMS_CAUSE_TO, truelight@0: STR_4833_SUPPLY_PROBLEMS_CAUSE_TO, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, truelight@0: STR_4833_SUPPLY_PROBLEMS_CAUSE_TO, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, truelight@0: STR_4834_LACK_OF_NEARBY_TREES_CAUSES, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, truelight@0: STR_4833_SUPPLY_PROBLEMS_CAUSE_TO, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, truelight@0: STR_4833_SUPPLY_PROBLEMS_CAUSE_TO, truelight@0: STR_4833_SUPPLY_PROBLEMS_CAUSE_TO, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, truelight@0: STR_4833_SUPPLY_PROBLEMS_CAUSE_TO, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE, tron@2639: STR_4832_ANNOUNCES_IMMINENT_CLOSURE truelight@0: }; truelight@0: truelight@0: Darkvater@2436: static void IndustryDrawTileProc1(const TileInfo *ti) truelight@0: { truelight@0: const DrawIndustrySpec1Struct *d; truelight@0: uint32 image; truelight@0: tron@2639: if (!(_m[ti->tile].m1 & 0x80)) return; truelight@201: tron@2049: d = &_draw_industry_spec1[_m[ti->tile].m3]; truelight@0: truelight@0: AddChildSpriteScreen(0x12A7 + d->image_1, d->x, 0); truelight@0: tron@2639: image = d->image_2; tron@2639: if (image != 0) AddChildSpriteScreen(0x12B0 + image - 1, 8, 41); truelight@0: tron@2639: image = d->image_3; tron@2639: if (image != 0) { truelight@201: AddChildSpriteScreen(0x12AC + image - 1, tron@2639: _drawtile_proc1_x[image - 1], _drawtile_proc1_y[image - 1]); tron@2639: } truelight@0: } truelight@0: Darkvater@2436: static void IndustryDrawTileProc2(const TileInfo *ti) truelight@0: { truelight@0: int x = 0; truelight@201: tron@2360: if (_m[ti->tile].m1 & 0x80) { tron@2049: x = _industry_anim_offs[_m[ti->tile].m3]; truelight@0: if ( (byte)x == 0xFF) truelight@0: x = 0; truelight@0: } truelight@0: tron@2639: AddChildSpriteScreen(0x129F, 22 - x, 24 + x); truelight@0: AddChildSpriteScreen(0x129E, 6, 0xE); truelight@0: } truelight@0: Darkvater@2436: static void IndustryDrawTileProc3(const TileInfo *ti) truelight@0: { tron@2360: if (_m[ti->tile].m1 & 0x80) { tron@2639: AddChildSpriteScreen(0x128B, 5, _industry_anim_offs_2[_m[ti->tile].m3]); tron@2639: } else { tron@2639: AddChildSpriteScreen(4746, 3, 67); truelight@0: } truelight@0: } truelight@0: Darkvater@2436: static void IndustryDrawTileProc4(const TileInfo *ti) truelight@0: { truelight@0: const DrawIndustrySpec4Struct *d; truelight@0: tron@2049: d = &_industry_anim_offs_3[_m[ti->tile].m3]; truelight@0: truelight@0: if (d->image_1 != 0xFF) { truelight@0: AddChildSpriteScreen(0x126F, 0x32 - d->image_1 * 2, 0x60 + d->image_1); truelight@0: } truelight@0: truelight@0: if (d->image_2 != 0xFF) { tron@2639: AddChildSpriteScreen(0x1270, 0x10 - d->image_2 * 2, 100 + d->image_2); truelight@0: } truelight@0: truelight@0: AddChildSpriteScreen(0x126E, 7, d->image_3); truelight@0: AddChildSpriteScreen(0x126D, 0, 42); truelight@0: } truelight@0: Darkvater@2436: static void DrawCoalPlantSparkles(const TileInfo *ti) truelight@0: { tron@2360: int image = _m[ti->tile].m1; truelight@0: if (image & 0x80) { tron@2140: image = GB(image, 2, 5); truelight@0: if (image != 0 && image < 7) { truelight@201: AddChildSpriteScreen(image + 0x806, tron@2639: _coal_plant_sparkles_x[image - 1], tron@2639: _coal_plant_sparkles_y[image - 1] truelight@0: ); truelight@0: } truelight@0: } truelight@0: } truelight@0: Darkvater@2436: typedef void IndustryDrawTileProc(const TileInfo *ti); truelight@0: static IndustryDrawTileProc * const _industry_draw_tile_procs[5] = { truelight@0: IndustryDrawTileProc1, truelight@0: IndustryDrawTileProc2, truelight@0: IndustryDrawTileProc3, truelight@0: IndustryDrawTileProc4, truelight@0: DrawCoalPlantSparkles, truelight@0: }; truelight@0: truelight@0: static void DrawTile_Industry(TileInfo *ti) truelight@0: { tron@2630: const Industry* ind; truelight@0: const DrawIndustryTileStruct *dits; truelight@0: byte z; truelight@0: uint32 image, ormod; truelight@0: truelight@0: /* Pointer to industry */ tron@2049: ind = GetIndustry(_m[ti->tile].m2); tron@2639: ormod = (ind->color_map + 0x307) << PALETTE_SPRITE_START; truelight@0: truelight@0: /* Retrieve pointer to the draw industry tile struct */ tron@2493: dits = &_industry_draw_tile_data[(ti->map5 << 2) | GB(_m[ti->tile].m1, 0, 2)]; truelight@0: truelight@0: image = dits->sprite_1; celestar@2187: if (image & PALETTE_MODIFIER_COLOR && (image & PALETTE_SPRITE_MASK) == 0) truelight@0: image |= ormod; truelight@0: truelight@0: z = ti->z; truelight@0: /* Add bricks below the industry? */ truelight@0: if (ti->tileh & 0xF) { tron@2535: AddSortableSpriteToDraw(SPR_FOUNDATION_BASE + (ti->tileh & 0xF), ti->x, ti->y, 16, 16, 7, z); truelight@0: AddChildSpriteScreen(image, 0x1F, 1); truelight@0: z += 8; truelight@0: } else { truelight@0: /* Else draw regular ground */ truelight@0: DrawGroundSprite(image); truelight@0: } truelight@0: truelight@0: /* Add industry on top of the ground? */ tron@2639: image = dits->sprite_2; tron@2639: if (image != 0) { celestar@2187: if (image & PALETTE_MODIFIER_COLOR && (image & PALETTE_SPRITE_MASK) == 0) truelight@0: image |= ormod; truelight@201: tron@2639: if (_display_opt & DO_TRANS_BUILDINGS) MAKE_TRANSPARENT(image); truelight@201: truelight@201: AddSortableSpriteToDraw(image, tron@2653: ti->x + dits->subtile_x, tron@2653: ti->y + dits->subtile_y, tron@2653: dits->width + 1, tron@2653: dits->height + 1, truelight@0: dits->dz, truelight@0: z); truelight@0: tron@2639: if (_display_opt & DO_TRANS_BUILDINGS) return; truelight@0: } truelight@0: tron@2639: { tron@2639: int proc = dits->proc - 1; tron@2639: if (proc >= 0) _industry_draw_tile_procs[proc](ti); truelight@0: } truelight@0: } truelight@0: truelight@0: tron@2537: static uint GetSlopeZ_Industry(const TileInfo* ti) tron@2537: { celestar@9944: return ti->z + (ti->tileh == 0 ? 0 : 8); truelight@0: } truelight@0: tron@2548: static uint GetSlopeTileh_Industry(const TileInfo* ti) tron@2548: { dominik@39: return 0; dominik@39: } dominik@39: tron@1977: static void GetAcceptedCargo_Industry(TileIndex tile, AcceptedCargo ac) truelight@0: { tron@2049: int m5 = _m[tile].m5; tron@2598: CargoID a; truelight@0: truelight@0: a = _industry_map5_accepts_1[m5]; tron@2598: if (a != CT_INVALID) ac[a] = (a == 0) ? 1 : 8; truelight@0: truelight@0: a = _industry_map5_accepts_2[m5]; tron@2598: if (a != CT_INVALID) ac[a] = 8; truelight@0: truelight@0: a = _industry_map5_accepts_3[m5]; tron@2598: if (a != CT_INVALID) ac[a] = 8; truelight@0: } truelight@0: tron@1977: static void GetTileDesc_Industry(TileIndex tile, TileDesc *td) truelight@0: { tron@2630: const Industry* i = GetIndustry(_m[tile].m2); truelight@0: truelight@0: td->owner = i->owner; truelight@0: td->str = STR_4802_COAL_MINE + i->type; tron@2360: if ((_m[tile].m1 & 0x80) == 0) { tron@534: SetDParamX(td->dparam, 0, td->str); truelight@0: td->str = STR_2058_UNDER_CONSTRUCTION; truelight@0: } truelight@0: } truelight@0: tron@1977: static int32 ClearTile_Industry(TileIndex tile, byte flags) truelight@0: { tron@2049: Industry *i = GetIndustry(_m[tile].m2); truelight@0: darkvater@149: /* * water can destroy industries darkvater@149: * in editor you can bulldoze industries darkvater@149: * with magic_bulldozer cheat you can destroy industries darkvater@149: * (area around OILRIG is water, so water shouldn't flood it darkvater@149: */ darkvater@149: if ((_current_player != OWNER_WATER && _game_mode != GM_EDITOR && darkvater@149: !_cheats.magic_bulldozer.value) || darkvater@149: (_current_player == OWNER_WATER && i->type == IT_OIL_RIG) ) { tron@534: SetDParam(0, STR_4802_COAL_MINE + i->type); truelight@0: return_cmd_error(STR_4800_IN_THE_WAY); truelight@0: } truelight@0: tron@2639: if (flags & DC_EXEC) DeleteIndustry(i); truelight@0: return 0; truelight@0: } truelight@0: truelight@0: truelight@0: static const byte _industry_min_cargo[] = { truelight@0: 5, 5, 5, 30, 5, 5, 5, 5, truelight@0: 5, 5, 5, 5, 2, 5, 5, 5, truelight@0: 5, 5, 5, 15, 15, 5, 5, 5, truelight@0: 5, 5, 30, 5, 30, 5, 5, 5, truelight@0: 5, 5, 5, 5, 5, truelight@0: }; truelight@0: tron@1977: static void TransportIndustryGoods(TileIndex tile) truelight@0: { tron@2639: Industry* i = GetIndustry(_m[tile].m2); truelight@0: uint cw, am; truelight@0: tron@2639: cw = min(i->cargo_waiting[0], 255); tron@2639: if (cw > _industry_min_cargo[i->type]/* && i->produced_cargo[0] != 0xFF*/) { tron@2639: byte m5; truelight@201: truelight@0: i->cargo_waiting[0] -= cw; truelight@0: truelight@0: /* fluctuating economy? */ tron@2639: if (_economy.fluct <= 0) cw = (cw + 1) / 2; truelight@0: truelight@0: i->last_mo_production[0] += cw; truelight@0: truelight@0: am = MoveGoodsToStation(i->xy, i->width, i->height, i->produced_cargo[0], cw); truelight@0: i->last_mo_transported[0] += am; tron@2049: if (am != 0 && (m5 = _industry_produce_map5[_m[tile].m5]) != 0xFF) { tron@2360: _m[tile].m1 = 0x80; tron@2049: _m[tile].m5 = m5; truelight@0: MarkTileDirtyByTile(tile); truelight@0: } truelight@0: } truelight@0: truelight@0: cw = min(i->cargo_waiting[1], 255); tron@2639: if (cw > _industry_min_cargo[i->type]) { truelight@0: i->cargo_waiting[1] -= cw; truelight@201: tron@2639: if (_economy.fluct <= 0) cw = (cw + 1) / 2; truelight@201: truelight@0: i->last_mo_production[1] += cw; truelight@0: truelight@0: am = MoveGoodsToStation(i->xy, i->width, i->height, i->produced_cargo[1], cw); truelight@0: i->last_mo_transported[1] += am; truelight@0: } truelight@0: } truelight@0: truelight@0: tron@1977: static void AnimateTile_Industry(TileIndex tile) truelight@0: { truelight@0: byte m,n; truelight@0: tron@2049: switch(_m[tile].m5) { truelight@0: case 174: truelight@0: if ((_tick_counter & 1) == 0) { tron@2049: m = _m[tile].m3 + 1; truelight@201: truelight@0: switch(m & 7) { tron@541: case 2: SndPlayTileFx(SND_2D_RIP_2, tile); break; tron@541: case 6: SndPlayTileFx(SND_29_RIP, tile); break; truelight@0: } truelight@0: truelight@0: if (m >= 96) { truelight@0: m = 0; truelight@0: DeleteAnimatedTile(tile); truelight@0: } tron@2049: _m[tile].m3 = m; truelight@0: truelight@0: MarkTileDirtyByTile(tile); truelight@0: } truelight@0: break; truelight@0: truelight@0: case 165: truelight@0: if ((_tick_counter & 3) == 0) { tron@2049: m = _m[tile].m3; truelight@201: truelight@0: if (_industry_anim_offs[m] == 0xFF) { tron@541: SndPlayTileFx(SND_30_CARTOON_SOUND, tile); truelight@0: } truelight@0: truelight@0: if (++m >= 70) { truelight@0: m = 0; truelight@0: DeleteAnimatedTile(tile); truelight@0: } tron@2049: _m[tile].m3 = m; truelight@0: truelight@0: MarkTileDirtyByTile(tile); truelight@0: } truelight@0: break; truelight@0: truelight@0: case 162: truelight@0: if ((_tick_counter&1) == 0) { tron@2049: m = _m[tile].m3; truelight@0: truelight@0: if (++m >= 40) { truelight@0: m = 0; truelight@0: DeleteAnimatedTile(tile); truelight@0: } tron@2049: _m[tile].m3 = m; truelight@0: truelight@0: MarkTileDirtyByTile(tile); truelight@0: } truelight@0: break; truelight@0: truelight@0: // Sparks on a coal plant truelight@0: case 10: truelight@0: if ((_tick_counter & 3) == 0) { tron@2360: m = _m[tile].m1; tron@2663: if (GB(m, 2, 5) == 6) { tron@2663: SB(_m[tile].m1, 2, 5, 0); truelight@0: DeleteAnimatedTile(tile); truelight@0: } else { tron@2360: _m[tile].m1 = m + (1<<2); truelight@0: MarkTileDirtyByTile(tile); truelight@0: } truelight@0: } truelight@0: break; truelight@0: truelight@0: case 143: truelight@0: if ((_tick_counter & 1) == 0) { tron@2049: m = _m[tile].m3 + 1; truelight@0: truelight@0: if (m == 1) { tron@541: SndPlayTileFx(SND_2C_MACHINERY, tile); truelight@0: } else if (m == 23) { tron@541: SndPlayTileFx(SND_2B_COMEDY_HIT, tile); truelight@0: } else if (m == 28) { tron@541: SndPlayTileFx(SND_2A_EXTRACT_AND_POP, tile); truelight@0: } truelight@0: tron@2049: if (m >= 50 && (m=0,++_m[tile].m4 >= 8)) { tron@2049: _m[tile].m4 = 0; truelight@0: DeleteAnimatedTile(tile); truelight@0: } tron@2049: _m[tile].m3 = m; truelight@0: MarkTileDirtyByTile(tile); truelight@0: } truelight@0: break; truelight@0: truelight@0: case 148: case 149: case 150: case 151: truelight@0: case 152: case 153: case 154: case 155: truelight@0: if ((_tick_counter & 3) == 0) { tron@2049: m = _m[tile].m5 + 1; truelight@0: if (m == 155+1) m = 148; tron@2049: _m[tile].m5 = m; truelight@0: truelight@0: MarkTileDirtyByTile(tile); truelight@0: } truelight@0: break; truelight@0: truelight@0: case 30: case 31: case 32: truelight@0: if ((_tick_counter & 7) == 0) { truelight@0: bool b = CHANCE16(1,7); tron@2360: m = _m[tile].m1; truelight@0: m = (m & 3) + 1; tron@2049: n = _m[tile].m5; truelight@0: if (m == 4 && (m=0,++n) == 32+1 && (n=30,b)) { tron@2360: _m[tile].m1 = 0x83; tron@2049: _m[tile].m5 = 29; truelight@201: DeleteAnimatedTile(tile); truelight@0: } else { tron@2663: SB(_m[tile].m1, 0, 2, m); tron@2049: _m[tile].m5 = n; truelight@0: MarkTileDirtyByTile(tile); truelight@0: } truelight@0: } truelight@0: break; truelight@0: truelight@0: case 88: truelight@0: case 48: truelight@0: case 1: { truelight@0: int state = _tick_counter & 0x7FF; truelight@0: truelight@0: if ((state -= 0x400) < 0) truelight@0: return; truelight@0: truelight@0: if (state < 0x1A0) { truelight@0: if (state < 0x20 || state >= 0x180) { tron@2360: if (!(_m[tile].m1 & 0x40)) { tron@2360: _m[tile].m1 |= 0x40; tron@541: SndPlayTileFx(SND_0B_MINING_MACHINERY, tile); truelight@0: } truelight@0: if (state & 7) truelight@0: return; truelight@0: } else { truelight@0: if (state & 3) truelight@0: return; truelight@0: } tron@2360: m = (_m[tile].m1 + 1) | 0x40; truelight@0: if (m > 0xC2) m = 0xC0; tron@2360: _m[tile].m1 = m; truelight@0: MarkTileDirtyByTile(tile); truelight@0: } else if (state >= 0x200 && state < 0x3A0) { truelight@0: int i; truelight@0: i = (state < 0x220 || state >= 0x380) ? 7 : 3; truelight@0: if (state & i) truelight@0: return; truelight@0: tron@2360: m = (_m[tile].m1 & 0xBF) - 1; truelight@0: if (m < 0x80) m = 0x82; tron@2360: _m[tile].m1 = m; truelight@0: MarkTileDirtyByTile(tile); truelight@0: } truelight@0: } break; truelight@0: } truelight@0: } truelight@0: tron@1977: static void MakeIndustryTileBiggerCase8(TileIndex tile) truelight@0: { truelight@0: TileInfo ti; tron@926: FindLandscapeHeight(&ti, TileX(tile) * 16, TileY(tile) * 16); tron@1359: CreateEffectVehicle(ti.x + 15, ti.y + 14, ti.z + 59 + (ti.tileh != 0 ? 8 : 0), EV_CHIMNEY_SMOKE); truelight@0: } truelight@0: tron@1977: static void MakeIndustryTileBigger(TileIndex tile, byte size) truelight@0: { truelight@0: byte b = (byte)((size + (1<<2)) & (3<<2)); truelight@0: truelight@0: if (b != 0) { tron@2360: _m[tile].m1 = b | (size & 3); truelight@0: return; truelight@0: } truelight@0: truelight@0: size = (size + 1) & 3; truelight@0: if (size == 3) size |= 0x80; tron@2360: _m[tile].m1 = size | b; truelight@201: truelight@0: MarkTileDirtyByTile(tile); truelight@0: tron@2360: if (!(_m[tile].m1 & 0x80)) truelight@0: return; truelight@0: tron@2049: switch(_m[tile].m5) { truelight@0: case 8: truelight@0: MakeIndustryTileBiggerCase8(tile); truelight@0: break; truelight@0: truelight@0: case 24: tron@2049: if (_m[tile + TileDiffXY(0, 1)].m5 == 24) BuildOilRig(tile); truelight@0: break; truelight@0: truelight@0: case 143: truelight@0: case 162: truelight@0: case 165: tron@2049: _m[tile].m3 = 0; tron@2049: _m[tile].m4 = 0; truelight@0: break; truelight@0: truelight@0: case 148: case 149: case 150: case 151: truelight@0: case 152: case 153: case 154: case 155: truelight@0: AddAnimatedTile(tile); truelight@0: break; truelight@0: } truelight@0: } truelight@0: truelight@0: tron@1977: static void TileLoopIndustryCase161(TileIndex tile) truelight@0: { truelight@0: int dir; truelight@0: Vehicle *v; truelight@0: static const int8 _tileloop_ind_case_161[12] = { truelight@0: 11, 0, -4, -14, truelight@0: -4, -10, -4, 1, truelight@0: 49, 59, 60, 65, truelight@0: }; truelight@0: tron@541: SndPlayTileFx(SND_2E_EXTRACT_AND_POP, tile); truelight@201: truelight@0: dir = Random() & 3; truelight@0: truelight@0: v = CreateEffectVehicleAbove( tron@926: TileX(tile) * 16 + _tileloop_ind_case_161[dir + 0], tron@926: TileY(tile) * 16 + _tileloop_ind_case_161[dir + 4], truelight@0: _tileloop_ind_case_161[dir + 8], tron@1359: EV_BUBBLE truelight@0: ); truelight@0: tron@2639: if (v != NULL) v->u.special.unk2 = dir; truelight@0: } truelight@0: tron@1977: static void TileLoop_Industry(TileIndex tile) truelight@0: { truelight@0: byte n; truelight@0: tron@2360: if (!(_m[tile].m1 & 0x80)) { tron@2360: MakeIndustryTileBigger(tile, _m[tile].m1); truelight@0: return; truelight@0: } truelight@0: tron@2639: if (_game_mode == GM_EDITOR) return; truelight@0: truelight@0: TransportIndustryGoods(tile); truelight@0: tron@2049: n = _industry_map5_animation_next[_m[tile].m5]; truelight@0: if (n != 255) { tron@2360: _m[tile].m1 = 0; tron@2049: _m[tile].m5 = n; truelight@0: MarkTileDirtyByTile(tile); truelight@0: return; truelight@0: } truelight@0: tron@2360: #define SET_AND_ANIMATE(tile, a, b) { _m[tile].m5 = a; _m[tile].m1 = b; AddAnimatedTile(tile); } tron@2360: #define SET_AND_UNANIMATE(tile, a, b) { _m[tile].m5 = a; _m[tile].m1 = b; DeleteAnimatedTile(tile); } truelight@0: tron@2639: switch (_m[tile].m5) { dominik@43: case 0x18: // coast line at oilrigs dominik@43: case 0x19: dominik@43: case 0x1A: dominik@43: case 0x1B: dominik@43: case 0x1C: dominik@43: TileLoop_Water(tile); dominik@43: break; dominik@43: truelight@0: case 0: truelight@0: if (!(_tick_counter & 0x400) && CHANCE16(1,2)) truelight@0: SET_AND_ANIMATE(tile,1,0x80); truelight@0: break; truelight@0: truelight@0: case 47: truelight@0: if (!(_tick_counter & 0x400) && CHANCE16(1,2)) truelight@0: SET_AND_ANIMATE(tile,0x30,0x80); truelight@0: break; truelight@0: truelight@0: case 79: truelight@0: if (!(_tick_counter & 0x400) && CHANCE16(1,2)) truelight@0: SET_AND_ANIMATE(tile,0x58,0x80); truelight@0: break; truelight@0: truelight@0: case 29: truelight@0: if (CHANCE16(1,6)) truelight@0: SET_AND_ANIMATE(tile,0x1E,0x80); truelight@0: break; truelight@0: truelight@0: case 1: truelight@0: if (!(_tick_counter & 0x400)) truelight@0: SET_AND_UNANIMATE(tile, 0, 0x83); truelight@0: break; truelight@0: truelight@0: case 48: truelight@0: if (!(_tick_counter & 0x400)) truelight@0: SET_AND_UNANIMATE(tile, 0x2F, 0x83); truelight@0: break; truelight@0: truelight@0: case 88: truelight@0: if (!(_tick_counter & 0x400)) truelight@0: SET_AND_UNANIMATE(tile, 0x4F, 0x83); truelight@0: break; truelight@0: truelight@0: case 10: truelight@0: if (CHANCE16(1,3)) { tron@541: SndPlayTileFx(SND_0C_ELECTRIC_SPARK, tile); truelight@0: AddAnimatedTile(tile); truelight@0: } truelight@0: break; truelight@0: tron@2639: case 49: tron@1359: CreateEffectVehicleAbove(TileX(tile) * 16 + 6, TileY(tile) * 16 + 6, 43, EV_SMOKE); tron@2639: break; truelight@0: truelight@0: truelight@0: case 143: { tron@2049: Industry *i = GetIndustry(_m[tile].m2); truelight@0: if (i->was_cargo_delivered) { truelight@0: i->was_cargo_delivered = false; ludde@2061: _m[tile].m4 = 0; truelight@0: AddAnimatedTile(tile); truelight@0: } truelight@0: } truelight@0: break; truelight@0: truelight@0: case 161: truelight@0: TileLoopIndustryCase161(tile); truelight@201: break; truelight@201: truelight@0: case 165: truelight@0: AddAnimatedTile(tile); truelight@0: break; truelight@0: truelight@0: case 174: tron@2639: if (CHANCE16(1, 3)) AddAnimatedTile(tile); truelight@0: break; truelight@0: } truelight@0: } truelight@0: truelight@0: tron@1977: static void ClickTile_Industry(TileIndex tile) truelight@0: { tron@2049: ShowIndustryViewWindow(_m[tile].m2); truelight@0: } truelight@0: tron@1977: static uint32 GetTileTrackStatus_Industry(TileIndex tile, TransportType mode) truelight@0: { truelight@0: return 0; truelight@0: } truelight@0: tron@1977: static void GetProducedCargo_Industry(TileIndex tile, byte *b) truelight@0: { tron@2630: const Industry* i = GetIndustry(_m[tile].m2); tron@2630: truelight@0: b[0] = i->produced_cargo[0]; truelight@0: b[1] = i->produced_cargo[1]; truelight@0: } truelight@0: Darkvater@2436: static void ChangeTileOwner_Industry(TileIndex tile, PlayerID old_player, PlayerID new_player) truelight@0: { truelight@0: /* not used */ truelight@0: } truelight@0: truelight@0: void DeleteIndustry(Industry *i) truelight@0: { truelight@919: BEGIN_TILE_LOOP(tile_cur, i->width, i->height, i->xy); tron@1035: if (IsTileType(tile_cur, MP_INDUSTRY)) { tron@2049: if (_m[tile_cur].m2 == i->index) { truelight@0: DoClearSquare(tile_cur); truelight@0: } tron@2049: } else if (IsTileType(tile_cur, MP_STATION) && _m[tile_cur].m5 == 0x4B) { truelight@0: DeleteOilRig(tile_cur); truelight@0: } truelight@919: END_TILE_LOOP(tile_cur, i->width, i->height, i->xy); truelight@201: truelight@0: i->xy = 0; truelight@0: _industry_sort_dirty = true; truelight@919: DeleteSubsidyWithIndustry(i->index); truelight@919: DeleteWindowById(WC_INDUSTRY_VIEW, i->index); truelight@0: InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0); truelight@0: } truelight@0: truelight@0: static const byte _plantfarmfield_type[] = {1, 1, 1, 1, 1, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6}; truelight@0: tron@1048: static bool IsBadFarmFieldTile(TileIndex tile) truelight@0: { tron@1214: switch (GetTileType(tile)) { tron@1048: case MP_CLEAR: { tron@2049: byte m5 = _m[tile].m5 & 0x1C; tron@1048: return m5 == 0xC || m5 == 0x10; tron@1048: } tron@1048: tron@1048: case MP_TREES: tron@1048: return false; tron@1048: tron@1048: default: truelight@0: return true; truelight@0: } truelight@0: } truelight@0: tron@1048: static bool IsBadFarmFieldTile2(TileIndex tile) truelight@0: { tron@1214: switch (GetTileType(tile)) { tron@1048: case MP_CLEAR: { tron@2049: byte m5 = _m[tile].m5 & 0x1C; tron@1048: return m5 == 0x10; tron@1048: } tron@1048: tron@1048: case MP_TREES: tron@1048: return false; tron@1048: tron@1048: default: truelight@0: return true; truelight@0: } truelight@0: } truelight@0: tron@1977: static void SetupFarmFieldFence(TileIndex tile, int size, byte type, int direction) truelight@0: { truelight@0: byte or, and; truelight@0: truelight@0: do { truelight@0: tile = TILE_MASK(tile); truelight@201: tron@1035: if (IsTileType(tile, MP_CLEAR) || IsTileType(tile, MP_TREES)) { truelight@201: truelight@0: or = type; tron@2637: if (or == 1 && CHANCE16(1, 7)) or = 2; truelight@0: truelight@0: or <<= 2; truelight@0: and = (byte)~0x1C; truelight@0: if (direction) { truelight@0: or <<= 3; truelight@0: and = (byte)~0xE0; truelight@0: } tron@2049: _m[tile].m4 = (_m[tile].m4 & and) | or; truelight@0: } truelight@201: tron@1981: tile += direction ? TileDiffXY(0, 1) : TileDiffXY(1, 0); truelight@0: } while (--size); truelight@0: } truelight@0: tron@1977: static void PlantFarmField(TileIndex tile) truelight@0: { truelight@0: uint size_x, size_y; truelight@0: uint32 r; tron@2133: uint count; truelight@0: int type, type2; truelight@0: truelight@0: if (_opt.landscape == LT_HILLY) { tron@1335: if (GetTileZ(tile) + 16 >= _opt.snow_line) truelight@0: return; truelight@0: } truelight@0: truelight@0: /* determine field size */ truelight@0: r = (Random() & 0x303) + 0x404; truelight@0: if (_opt.landscape == LT_HILLY) r += 0x404; tron@2150: size_x = GB(r, 0, 8); tron@2150: size_y = GB(r, 8, 8); truelight@0: truelight@0: /* offset tile to match size */ tron@1981: tile -= TileDiffXY(size_x / 2, size_y / 2); truelight@201: truelight@0: /* check the amount of bad tiles */ truelight@0: count = 0; truelight@0: BEGIN_TILE_LOOP(cur_tile, size_x, size_y, tile) truelight@0: cur_tile = TILE_MASK(cur_tile); truelight@0: count += IsBadFarmFieldTile(cur_tile); truelight@0: END_TILE_LOOP(cur_tile, size_x, size_y, tile) tron@2133: if (count * 2 >= size_x * size_y) return; truelight@0: truelight@0: /* determine type of field */ truelight@0: r = Random(); truelight@0: type = ((r & 0xE0) | 0xF); tron@2150: type2 = GB(r, 8, 8) * 9 >> 8; truelight@0: truelight@0: /* make field */ truelight@0: BEGIN_TILE_LOOP(cur_tile, size_x, size_y, tile) truelight@0: cur_tile = TILE_MASK(cur_tile); truelight@0: if (!IsBadFarmFieldTile2(cur_tile)) { truelight@201: ModifyTile(cur_tile, truelight@201: MP_SETTYPE(MP_CLEAR) | truelight@0: MP_MAP2_CLEAR | MP_MAP3LO | MP_MAP3HI_CLEAR | MP_MAPOWNER | MP_MAP5, truelight@0: type2, /* map3_lo */ truelight@0: OWNER_NONE, /* map_owner */ truelight@0: type); /* map5 */ truelight@0: } truelight@0: END_TILE_LOOP(cur_tile, size_x, size_y, tile) truelight@201: truelight@0: type = 3; truelight@0: if (_opt.landscape != LT_HILLY && _opt.landscape != LT_DESERT) { truelight@0: type = _plantfarmfield_type[Random() & 0xF]; truelight@0: } truelight@0: tron@1981: SetupFarmFieldFence(tile - TileDiffXY(1, 0), size_y, type, 1); tron@1981: SetupFarmFieldFence(tile - TileDiffXY(0, 1), size_x, type, 0); tron@1981: SetupFarmFieldFence(tile + TileDiffXY(size_x - 1, 0), size_y, type, 1); tron@1981: SetupFarmFieldFence(tile + TileDiffXY(0, size_y - 1), size_x, type, 0); truelight@0: } truelight@0: tron@2548: static void MaybePlantFarmField(const Industry* i) truelight@0: { tron@2549: if (CHANCE16(1, 8)) { tron@2549: int x = i->width / 2 + Random() % 31 - 16; tron@2549: int y = i->height / 2 + Random() % 31 - 16; tron@2549: TileIndex tile = TileAddWrap(i->xy, x, y); tron@2549: if (tile != INVALID_TILE) PlantFarmField(tile); truelight@201: } truelight@0: } truelight@0: truelight@0: static void ChopLumberMillTrees(Industry *i) truelight@0: { tron@909: static const TileIndexDiffC _chop_dir[] = { tron@909: { 0, 1}, tron@909: { 1, 0}, tron@909: { 0, -1}, tron@909: {-1, 0} tron@909: }; truelight@201: tron@1977: TileIndex tile = i->xy; tron@2639: int a; truelight@0: tron@2639: if ((_m[tile].m1 & 0x80) == 0) return; truelight@0: truelight@0: /* search outwards as a rectangular spiral */ tron@2639: for (a = 1; a != 41; a += 2) { tron@2639: uint dir; tron@2639: tron@2639: for (dir = 0; dir != 4; dir++) { tron@2639: int j = a; tron@2639: truelight@0: do { truelight@0: tile = TILE_MASK(tile); tron@1035: if (IsTileType(tile, MP_TREES)) { tron@2498: PlayerID old_player = _current_player; truelight@0: /* found a tree */ truelight@0: truelight@0: _current_player = OWNER_NONE; truelight@0: _industry_sound_ctr = 1; truelight@0: _industry_sound_tile = tile; tron@541: SndPlayTileFx(SND_38_CHAINSAW, tile); truelight@0: truelight@0: DoCommandByTile(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); truelight@0: SetMapExtraBits(tile, 0); truelight@0: truelight@0: i->cargo_waiting[0] = min(0xffff, i->cargo_waiting[0] + 45); truelight@314: truelight@314: _current_player = old_player; truelight@0: return; truelight@0: } tron@909: tile += ToTileIndexDiff(_chop_dir[dir]); truelight@0: } while (--j); truelight@0: } tron@1981: tile -= TileDiffXY(1, 1); truelight@0: } truelight@0: } truelight@0: truelight@0: static const byte _industry_sounds[37][2] = { truelight@0: {0}, truelight@0: {0}, tron@541: {1, SND_28_SAWMILL}, truelight@0: {0}, truelight@0: {0}, truelight@0: {0}, tron@541: {1, SND_03_FACTORY_WHISTLE}, tron@541: {1, SND_03_FACTORY_WHISTLE}, truelight@0: {0}, tron@541: {3, SND_24_SHEEP}, truelight@0: {0}, truelight@0: {0}, truelight@0: {0}, truelight@0: {0}, tron@541: {1, SND_28_SAWMILL}, truelight@0: {0}, truelight@0: {0}, truelight@0: {0}, truelight@0: {0}, truelight@0: {0}, truelight@0: {0}, truelight@0: {0}, truelight@0: {0}, tron@541: {1, SND_03_FACTORY_WHISTLE}, truelight@0: {0}, truelight@0: {0}, truelight@0: {0}, truelight@0: {0}, truelight@0: {0}, truelight@0: {0}, truelight@0: {0}, truelight@0: {0}, tron@541: {1, SND_33_PLASTIC_MINE}, truelight@0: {0}, truelight@0: {0}, truelight@0: {0}, truelight@0: {0}, truelight@0: }; truelight@0: truelight@0: truelight@0: static void ProduceIndustryGoods(Industry *i) truelight@0: { truelight@0: uint32 r; truelight@0: uint num; truelight@0: truelight@0: /* play a sound? */ truelight@0: if ((i->counter & 0x3F) == 0) { truelight@0: if (CHANCE16R(1,14,r) && (num=_industry_sounds[i->type][0]) != 0) { truelight@0: SndPlayTileFx( truelight@0: _industry_sounds[i->type][1] + (((r >> 16) * num) >> 16), truelight@0: i->xy); truelight@0: } truelight@0: } truelight@0: truelight@0: i->counter--; truelight@0: truelight@0: /* produce some cargo */ truelight@0: if ((i->counter & 0xFF) == 0) { truelight@0: i->cargo_waiting[0] = min(0xffff, i->cargo_waiting[0] + i->production_rate[0]); truelight@0: i->cargo_waiting[1] = min(0xffff, i->cargo_waiting[1] + i->production_rate[1]); truelight@0: tron@2639: if (i->type == IT_FARM) { truelight@0: MaybePlantFarmField(i); tron@2639: } else if (i->type == IT_LUMBER_MILL && (i->counter & 0x1FF) == 0) { truelight@0: ChopLumberMillTrees(i); tron@2639: } truelight@0: } truelight@0: } truelight@0: tron@1093: void OnTick_Industry(void) truelight@0: { truelight@0: Industry *i; truelight@0: truelight@0: if (_industry_sound_ctr != 0) { truelight@0: _industry_sound_ctr++; truelight@0: truelight@0: if (_industry_sound_ctr == 75) { tron@541: SndPlayTileFx(SND_37_BALLOON_SQUEAK, _industry_sound_tile); truelight@0: } else if (_industry_sound_ctr == 160) { truelight@201: _industry_sound_ctr = 0; tron@541: SndPlayTileFx(SND_36_CARTOON_CRASH, _industry_sound_tile); truelight@0: } truelight@0: } truelight@0: tron@2639: if (_game_mode == GM_EDITOR) return; truelight@0: truelight@830: FOR_ALL_INDUSTRIES(i) { tron@2639: if (i->xy != 0) ProduceIndustryGoods(i); truelight@0: } truelight@0: } truelight@0: truelight@0: tron@1977: static bool CheckNewIndustry_NULL(TileIndex tile, int type) truelight@0: { truelight@0: return true; truelight@0: } truelight@0: tron@1977: static bool CheckNewIndustry_Forest(TileIndex tile, int type) truelight@0: { truelight@0: if (_opt.landscape == LT_HILLY) { tron@1335: if (GetTileZ(tile) < _opt.snow_line + 16U) { truelight@0: _error_message = STR_4831_FOREST_CAN_ONLY_BE_PLANTED; truelight@0: return false; truelight@0: } truelight@0: } truelight@0: return true; truelight@0: } truelight@0: dominik@7: extern bool _ignore_restrictions; dominik@7: pasky@1586: /* Oil Rig and Oil Refinery */ tron@1977: static bool CheckNewIndustry_Oil(TileIndex tile, int type) truelight@0: { tron@2639: if (_game_mode == GM_EDITOR && _ignore_restrictions) return true; tron@2639: if (_game_mode == GM_EDITOR && type != IT_OIL_RIG) return true; peter1138@2868: if ((type != IT_OIL_RIG || TileHeight(tile) == 0) && peter1138@2868: DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < 16) return true; truelight@0: truelight@0: _error_message = STR_483B_CAN_ONLY_BE_POSITIONED; truelight@0: return false; truelight@0: } truelight@0: tron@1977: static bool CheckNewIndustry_Farm(TileIndex tile, int type) truelight@0: { truelight@0: if (_opt.landscape == LT_HILLY) { tron@1335: if (GetTileZ(tile) + 16 >= _opt.snow_line) { truelight@0: _error_message = STR_0239_SITE_UNSUITABLE; truelight@0: return false; truelight@0: } truelight@0: } truelight@0: return true; truelight@0: } truelight@0: tron@1977: static bool CheckNewIndustry_Plantation(TileIndex tile, int type) truelight@0: { truelight@0: if (GetMapExtraBits(tile) == 1) { truelight@0: _error_message = STR_0239_SITE_UNSUITABLE; truelight@0: return false; truelight@0: } truelight@0: truelight@0: return true; truelight@0: } truelight@0: tron@1977: static bool CheckNewIndustry_Water(TileIndex tile, int type) truelight@0: { truelight@0: if (GetMapExtraBits(tile) != 1) { truelight@0: _error_message = STR_0318_CAN_ONLY_BE_BUILT_IN_DESERT; truelight@0: return false; truelight@0: } truelight@0: truelight@0: return true; truelight@0: } truelight@0: tron@1977: static bool CheckNewIndustry_Lumbermill(TileIndex tile, int type) truelight@0: { truelight@0: if (GetMapExtraBits(tile) != 2) { truelight@0: _error_message = STR_0317_CAN_ONLY_BE_BUILT_IN_RAINFOREST; truelight@0: return false; truelight@0: } truelight@0: return true; truelight@0: } truelight@0: tron@1977: static bool CheckNewIndustry_BubbleGen(TileIndex tile, int type) truelight@0: { tron@2549: return GetTileZ(tile) <= 32; truelight@0: } truelight@0: tron@1977: typedef bool CheckNewIndustryProc(TileIndex tile, int type); truelight@0: static CheckNewIndustryProc * const _check_new_industry_procs[] = { truelight@0: CheckNewIndustry_NULL, truelight@0: CheckNewIndustry_Forest, pasky@1586: CheckNewIndustry_Oil, truelight@0: CheckNewIndustry_Farm, truelight@0: CheckNewIndustry_Plantation, truelight@0: CheckNewIndustry_Water, truelight@0: CheckNewIndustry_Lumbermill, truelight@0: CheckNewIndustry_BubbleGen, truelight@0: }; truelight@0: tron@1977: static bool CheckSuitableIndustryPos(TileIndex tile) truelight@0: { tron@926: uint x = TileX(tile); tron@926: uint y = TileY(tile); truelight@0: tron@2639: if (x < 2 || y < 2 || x > MapMaxX() - 3 || y > MapMaxY() - 3) { truelight@0: _error_message = STR_0239_SITE_UNSUITABLE; truelight@0: return false; truelight@0: } truelight@0: truelight@0: return true; truelight@0: } truelight@0: tron@2630: static const Town* CheckMultipleIndustryInTown(TileIndex tile, int type) truelight@0: { tron@2630: const Town* t; tron@2630: const Industry* i; truelight@0: truelight@0: t = ClosestTownFromTile(tile, (uint)-1); truelight@201: tron@2639: if (_patches.multiple_industry_per_town) return t; truelight@0: truelight@830: FOR_ALL_INDUSTRIES(i) { truelight@0: if (i->xy != 0 && truelight@0: i->type == (byte)type && truelight@0: i->town == t) { truelight@0: _error_message = STR_0287_ONLY_ONE_ALLOWED_PER_TOWN; truelight@0: return NULL; truelight@0: } truelight@0: } truelight@0: truelight@0: return t; truelight@0: } truelight@0: truelight@0: static const byte _industry_map5_bits[] = { truelight@0: 16, 16, 16, 16, 16, 16, 16, 16, truelight@0: 16, 16, 16, 16, 16, 16, 16, 16, truelight@0: 16, 16, 16, 16, 16, 16, 16, 16, truelight@0: 16, 16, 16, 16, 16, 16, 16, 16, truelight@0: 16, 16, 16, 16, 16, 16, 16, 16, truelight@0: 16, 16, 16, 16, 16, 16, 16, 16, truelight@0: 16, 16, 16, 16, 16, 16, 16, 16, truelight@0: 16, 16, 4, 2, 16, 16, 16, 16, truelight@0: 16, 16, 16, 16, 16, 16, 16, 16, truelight@0: 16, 16, 16, 16, 16, 16, 16, 16, truelight@0: 16, 16, 16, 16, 16, 16, 16, 16, truelight@0: 16, 4, 2, 16, 16, 16, 16, 16, truelight@0: 16, 16, 16, 16, 16, 16, 16, 16, truelight@0: 16, 16, 16, 16, 16, 16, 16, 16, truelight@0: 16, 16, 16, 16, 16, 16, 16, 16, truelight@0: 16, 16, 16, 16, 16, 16, 16, 16, truelight@0: 16, 16, 16, 16, 16, 16, 16, 16, truelight@0: 16, 16, 16, 16, 16, 16, 16, 16, truelight@0: 16, 16, 16, 16, 16, 16, 16, 16, truelight@0: 16, 16, 16, 16, 16, 16, 16, 16, truelight@0: 16, 16, 16, 16, 16, 16, 16, 16, truelight@0: 16, 16, 16, 16, 16, 16, 16, truelight@0: }; truelight@0: tron@2630: static bool CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTileTable* it, int type, const Town* t) truelight@0: { truelight@0: TileInfo ti; truelight@0: truelight@0: _error_message = STR_0239_SITE_UNSUITABLE; truelight@0: truelight@0: do { tron@1977: TileIndex cur_tile = tile + ToTileIndexDiff(it->ti); tron@1977: truelight@0: if (!IsValidTile(cur_tile)) { tron@2639: if (it->map5 == 0xff) continue; truelight@0: return false; truelight@0: } truelight@201: truelight@0: FindLandscapeHeightByTile(&ti, cur_tile); truelight@201: truelight@0: if (it->map5 == 0xFF) { tron@2639: if (ti.type != MP_WATER || ti.tileh != 0) return false; truelight@0: } else { tron@2639: if (!EnsureNoVehicle(cur_tile)) return false; truelight@0: truelight@0: if (type == IT_OIL_RIG) { tron@2639: if (ti.type != MP_WATER || ti.map5 != 0) return false; truelight@0: } else { tron@2639: if (ti.type == MP_WATER && ti.map5 == 0) return false; celestar@2085: if (IsSteepTileh(ti.tileh)) truelight@0: return false; truelight@0: truelight@0: if (ti.tileh != 0) { truelight@0: int t; truelight@0: byte bits = _industry_map5_bits[it->map5]; truelight@0: tron@2639: if (bits & 0x10) return false; truelight@201: truelight@0: t = ~ti.tileh; truelight@0: tron@2639: if (bits & 1 && (t & (1 + 8))) return false; tron@2639: if (bits & 2 && (t & (4 + 8))) return false; tron@2639: if (bits & 4 && (t & (1 + 2))) return false; tron@2639: if (bits & 8 && (t & (2 + 4))) return false; truelight@0: } truelight@0: truelight@0: if (type == IT_BANK) { truelight@0: if (ti.type != MP_HOUSE || t->population < 1200) { truelight@0: _error_message = STR_029D_CAN_ONLY_BE_BUILT_IN_TOWNS; truelight@0: return false; truelight@0: } truelight@0: } else if (type == IT_BANK_2) { truelight@0: if (ti.type != MP_HOUSE) { truelight@0: _error_message = STR_030D_CAN_ONLY_BE_BUILT_IN_TOWNS; truelight@0: return false; truelight@0: } truelight@0: } else if (type == IT_TOY_SHOP) { tron@2639: if (DistanceMax(t->xy, cur_tile) > 9) return false; truelight@0: if (ti.type != MP_HOUSE) goto do_clear; truelight@0: } else if (type == IT_WATER_TOWER) { truelight@0: if (ti.type != MP_HOUSE) { truelight@0: _error_message = STR_0316_CAN_ONLY_BE_BUILT_IN_TOWNS; truelight@0: return false; truelight@201: } truelight@0: } else { truelight@0: do_clear: peter1138@2737: if (CmdFailed(DoCommandByTile(cur_tile, 0, 0, DC_AUTO, CMD_LANDSCAPE_CLEAR))) truelight@0: return false; truelight@0: } truelight@0: } truelight@0: } tron@909: } while ((++it)->ti.x != -0x80); truelight@0: truelight@0: return true; truelight@0: } truelight@0: tron@1977: static bool CheckIfTooCloseToIndustry(TileIndex tile, int type) truelight@0: { tron@2639: const IndustrySpec* spec = &_industry_spec[type]; tron@2548: const Industry* i; truelight@0: truelight@0: // accepting industries won't be close, not even with patch tron@2469: if (_patches.same_industry_close && spec->accepts_cargo[0] == CT_INVALID) truelight@0: return true; truelight@201: truelight@830: FOR_ALL_INDUSTRIES(i) { truelight@0: // check if an industry that accepts the same goods is nearby truelight@0: if (i->xy != 0 && tron@2639: DistanceMax(tile, i->xy) <= 14 && tron@2469: spec->accepts_cargo[0] != CT_INVALID && tron@2639: spec->accepts_cargo[0] == i->accepts_cargo[0] && ( tron@2639: _game_mode != GM_EDITOR || tron@2639: !_patches.same_industry_close || tron@2639: !_patches.multiple_industry_per_town tron@2639: )) { tron@2639: _error_message = STR_INDUSTRY_TOO_CLOSE; tron@2639: return false; tron@2639: } truelight@0: truelight@0: // check "not close to" field. truelight@0: if (i->xy != 0 && truelight@0: (i->type == spec->a || i->type == spec->b || i->type == spec->c) && tron@1245: DistanceMax(tile, i->xy) <= 14) { truelight@0: _error_message = STR_INDUSTRY_TOO_CLOSE; truelight@0: return false; truelight@0: } truelight@0: } truelight@0: return true; truelight@0: } truelight@0: tron@1093: static Industry *AllocateIndustry(void) truelight@0: { truelight@0: Industry *i; truelight@0: truelight@830: FOR_ALL_INDUSTRIES(i) { truelight@0: if (i->xy == 0) { truelight@1267: uint index = i->index; truelight@1267: tron@2639: if (i->index > _total_industries) _total_industries = i->index; truelight@919: tron@2639: memset(i, 0, sizeof(*i)); truelight@1267: i->index = index; truelight@1267: truelight@0: return i; truelight@0: } truelight@0: } truelight@1267: truelight@1267: /* Check if we can add a block to the pool */ tron@2549: return AddBlockToPool(&_industry_pool) ? AllocateIndustry() : NULL; truelight@0: } truelight@0: tron@2630: static void DoCreateNewIndustry(Industry* i, TileIndex tile, int type, const IndustryTileTable* it, const Town* t, byte owner) truelight@0: { truelight@0: const IndustrySpec *spec; truelight@0: uint32 r; truelight@0: int j; truelight@0: truelight@0: i->xy = tile; truelight@0: i->width = i->height = 0; truelight@0: i->type = type; truelight@0: truelight@0: spec = &_industry_spec[type]; truelight@0: truelight@0: i->produced_cargo[0] = spec->produced_cargo[0]; truelight@0: i->produced_cargo[1] = spec->produced_cargo[1]; truelight@0: i->accepts_cargo[0] = spec->accepts_cargo[0]; truelight@0: i->accepts_cargo[1] = spec->accepts_cargo[1]; truelight@0: i->accepts_cargo[2] = spec->accepts_cargo[2]; truelight@0: i->production_rate[0] = spec->production_rate[0]; truelight@0: i->production_rate[1] = spec->production_rate[1]; truelight@0: truelight@0: if (_patches.smooth_economy) { truelight@0: i->production_rate[0] = min((RandomRange(256) + 128) * i->production_rate[0] >> 8 , 255); truelight@0: i->production_rate[1] = min((RandomRange(256) + 128) * i->production_rate[1] >> 8 , 255); truelight@0: } truelight@0: truelight@0: i->town = t; truelight@0: i->owner = owner; truelight@0: tron@2484: r = Random(); peter1138@2492: i->color_map = GB(r, 8, 4); peter1138@2492: i->counter = GB(r, 0, 12); truelight@0: i->cargo_waiting[0] = 0; truelight@0: i->cargo_waiting[1] = 0; truelight@0: i->last_mo_production[0] = 0; truelight@0: i->last_mo_production[1] = 0; truelight@0: i->last_mo_transported[0] = 0; truelight@0: i->last_mo_transported[1] = 0; truelight@0: i->pct_transported[0] = 0; truelight@0: i->pct_transported[1] = 0; truelight@0: i->total_transported[0] = 0; truelight@0: i->total_transported[1] = 0; truelight@0: i->was_cargo_delivered = false; truelight@0: i->last_prod_year = _cur_year; truelight@0: i->total_production[0] = i->production_rate[0] * 8; truelight@0: i->total_production[1] = i->production_rate[1] * 8; truelight@0: tron@2639: if (!_generating_world) i->total_production[0] = i->total_production[1] = 0; truelight@201: truelight@0: i->prod_level = 0x10; truelight@0: truelight@0: do { tron@1977: TileIndex cur_tile = tile + ToTileIndexDiff(it->ti); truelight@0: truelight@0: if (it->map5 != 0xFF) { truelight@0: byte size; truelight@0: tron@909: size = it->ti.x; truelight@0: if (size > i->width) i->width = size; tron@909: size = it->ti.y; truelight@0: if (size > i->height)i->height = size; truelight@0: truelight@0: DoCommandByTile(cur_tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); truelight@0: tron@1059: SetTileType(cur_tile, MP_INDUSTRY); tron@2049: _m[cur_tile].m5 = it->map5; tron@2049: _m[cur_tile].m2 = i->index; tron@2360: _m[cur_tile].m1 = _generating_world ? 0x1E : 0; /* maturity */ truelight@0: } tron@909: } while ((++it)->ti.x != -0x80); truelight@0: truelight@0: i->width++; truelight@0: i->height++; truelight@0: truelight@0: if (i->type == IT_FARM || i->type == IT_FARM_2) { tron@1981: tile = i->xy + TileDiffXY(i->width / 2, i->height / 2); tron@2639: for (j = 0; j != 50; j++) { truelight@543: int x = Random() % 31 - 16; truelight@543: int y = Random() % 31 - 16; tron@2639: TileIndex new_tile = TileAddWrap(tile, x, y); tron@1977: tron@2639: if (new_tile != INVALID_TILE) PlantFarmField(new_tile); truelight@131: } truelight@0: } truelight@0: _industry_sort_dirty = true; truelight@0: InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0); truelight@0: } truelight@0: Darkvater@1786: /** Build/Fund an industry Darkvater@1786: * @param x,y coordinates where industry is built Darkvater@1786: * @param p1 industry type @see build_industry.h and @see industry.h Darkvater@1786: * @param p2 unused Darkvater@1786: */ truelight@0: int32 CmdBuildIndustry(int x, int y, uint32 flags, uint32 p1, uint32 p2) truelight@0: { tron@2630: const Town* t; Darkvater@1786: Industry *i; tron@1980: TileIndex tile = TileVirtXY(x, y); truelight@0: int num; truelight@0: const IndustryTileTable * const *itt; truelight@0: const IndustryTileTable *it; truelight@0: const IndustrySpec *spec; truelight@0: truelight@0: SET_EXPENSES_TYPE(EXPENSES_OTHER); truelight@0: Darkvater@1786: if (!CheckSuitableIndustryPos(tile)) return CMD_ERROR; Darkvater@1786: Darkvater@1786: /* Check if the to-be built/founded industry is available for this climate. Darkvater@1786: * Unfortunately we have no easy way of checking, except for looping the table */ tron@2639: { tron@2639: const byte* i; Darkvater@1786: bool found = false; tron@2639: Darkvater@1786: for (i = &_build_industry_types[_opt_ptr->landscape][0]; i != endof(_build_industry_types[_opt_ptr->landscape]); i++) { tron@2639: if (*i == p1) { tron@2639: found = true; tron@2639: break; tron@2639: } Darkvater@1786: } Darkvater@1786: if (!found) return CMD_ERROR; Darkvater@1786: } truelight@0: truelight@0: spec = &_industry_spec[p1]; tron@2638: /* If the patch for raw-material industries is not on, you cannot build raw-material industries. Darkvater@1800: * Raw material industries are industries that do not accept cargo (at least for now) tron@2638: * Exclude the lumber mill (only "raw" industry that can be built) */ tron@2638: if (!_patches.build_rawmaterial_ind && tron@2638: spec->accepts_cargo[0] == CT_INVALID && tron@2638: spec->accepts_cargo[1] == CT_INVALID && tron@2638: spec->accepts_cargo[2] == CT_INVALID && tron@2638: p1 != IT_LUMBER_MILL) { tron@2638: return CMD_ERROR; tron@2638: } truelight@0: Darkvater@1786: if (!_check_new_industry_procs[spec->check_proc](tile, p1)) return CMD_ERROR; truelight@0: tron@2639: t = CheckMultipleIndustryInTown(tile, p1); tron@2639: if (t == NULL) return CMD_ERROR; truelight@201: truelight@0: num = spec->num_table; truelight@0: itt = spec->table; truelight@0: truelight@0: do { Darkvater@1786: if (--num < 0) return_cmd_error(STR_0239_SITE_UNSUITABLE); Darkvater@1786: } while (!CheckIfIndustryTilesAreFree(tile, it = itt[num], p1, t)); truelight@0: truelight@0: Darkvater@1786: if (!CheckIfTooCloseToIndustry(tile, p1)) return CMD_ERROR; truelight@0: tron@2639: i = AllocateIndustry(); tron@2639: if (i == NULL) return CMD_ERROR; truelight@0: tron@2639: if (flags & DC_EXEC) DoCreateNewIndustry(i, tile, p1, it, t, OWNER_NONE); truelight@201: truelight@0: return (_price.build_industry >> 5) * _industry_type_costs[p1]; truelight@0: } truelight@0: truelight@0: tron@1977: Industry *CreateNewIndustry(TileIndex tile, int type) truelight@0: { tron@2630: const Town* t; truelight@0: const IndustryTileTable *it; truelight@0: Industry *i; truelight@0: truelight@0: const IndustrySpec *spec; truelight@0: tron@2639: if (!CheckSuitableIndustryPos(tile)) return NULL; truelight@0: truelight@0: spec = &_industry_spec[type]; truelight@0: tron@2639: if (!_check_new_industry_procs[spec->check_proc](tile, type)) return NULL; truelight@0: tron@2639: t = CheckMultipleIndustryInTown(tile, type); tron@2639: if (t == NULL) return NULL; truelight@0: truelight@0: /* pick a random layout */ tron@2639: it = spec->table[RandomRange(spec->num_table)]; truelight@0: tron@2639: if (!CheckIfIndustryTilesAreFree(tile, it, type, t)) return NULL; tron@2639: if (!CheckIfTooCloseToIndustry(tile, type)) return NULL; truelight@0: tron@2639: i = AllocateIndustry(); tron@2639: if (i == NULL) return NULL; truelight@0: tron@2638: DoCreateNewIndustry(i, tile, type, it, t, OWNER_NONE); truelight@201: truelight@0: return i; truelight@0: } truelight@0: truelight@110: static const byte _numof_industry_table[4][12] = { orudge@61: {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, truelight@0: {0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5}, truelight@0: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, truelight@0: {0, 2, 3, 4, 6, 7, 8, 9, 10, 10, 10}, truelight@0: }; truelight@0: truelight@0: static void PlaceInitialIndustry(byte type, int amount) truelight@0: { ludde@2072: int num = _numof_industry_table[_opt.diff.number_industries][amount]; ludde@2072: ludde@2072: if (type == IT_OIL_REFINERY || type == IT_OIL_RIG) { ludde@2072: // These are always placed next to the coastline, so we scale by the perimeter instead. ludde@2072: num = ScaleByMapSize1D(num); ludde@2072: } else { ludde@2072: num = ScaleByMapSize(num); ludde@2072: } truelight@110: tron@2639: if (_opt.diff.number_industries != 0) { tron@2498: PlayerID old_player = _current_player; darkvater@266: _current_player = OWNER_NONE; orudge@61: assert(num > 0); truelight@0: truelight@0: do { tron@2639: uint i; tron@2639: tron@2639: for (i = 0; i < 2000; i++) { tron@2639: if (CreateNewIndustry(RandomTile(), type) != NULL) break; tron@2639: } truelight@110: } while (--num); darkvater@266: darkvater@267: _current_player = old_player; orudge@61: } truelight@0: } truelight@0: tron@1093: void GenerateIndustries(void) truelight@0: { truelight@0: const byte *b; truelight@0: truelight@0: b = _industry_create_table[_opt.landscape]; truelight@0: do { truelight@0: PlaceInitialIndustry(b[1], b[0]); truelight@0: } while ( (b+=2)[0] != 0); truelight@0: } truelight@0: truelight@0: static void ExtChangeIndustryProduction(Industry *i) truelight@0: { truelight@1320: bool closeit = true; truelight@0: int j; truelight@0: truelight@1320: switch (_industry_close_mode[i->type]) { truelight@1320: case INDUSTRY_NOT_CLOSABLE: truelight@1320: return; truelight@201: truelight@1320: case INDUSTRY_CLOSABLE: pasky@1603: if ((byte)(_cur_year - i->last_prod_year) < 5 || !CHANCE16(1, 180)) truelight@0: closeit = false; truelight@1320: break; truelight@201: truelight@1320: default: /* INDUSTRY_PRODUCTION */ tron@2638: for (j = 0; j < 2 && i->produced_cargo[j] != CT_INVALID; j++){ pasky@1603: uint32 r = Random(); pasky@1603: int old, new, percent; truelight@1320: int mag; truelight@1320: pasky@1603: new = old = i->production_rate[j]; pasky@1603: if (CHANCE16I(20, 1024, r)) pasky@1603: new -= ((RandomRange(50) + 10) * old) >> 8; pasky@1603: if (CHANCE16I(20 + (i->pct_transported[j] * 20 >> 8), 1024, r >> 16)) pasky@1603: new += ((RandomRange(50) + 10) * old) >> 8; truelight@1320: pasky@1603: new = clamp(new, 0, 255); pasky@1603: if (new == old) { truelight@1320: closeit = false; truelight@1320: continue; truelight@1320: } truelight@1320: pasky@1603: percent = new * 100 / old - 100; pasky@1603: i->production_rate[j] = new; truelight@1320: pasky@1603: if (new >= _industry_spec[i->type].production_rate[j] / 4) truelight@1320: closeit = false; truelight@1320: truelight@1320: mag = abs(percent); truelight@1320: if (mag >= 10) { ludde@2070: SetDParam(2, mag); pasky@1603: SetDParam(0, _cargoc.names_s[i->produced_cargo[j]]); ludde@2070: SetDParam(1, i->index); tron@2639: AddNewsItem( tron@2639: percent >= 0 ? STR_INDUSTRY_PROD_GOUP : STR_INDUSTRY_PROD_GODOWN, tron@2639: NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_TILE, NT_ECONOMY, 0), tron@2639: i->xy + TileDiffXY(1, 1), 0 tron@2639: ); truelight@1320: } truelight@0: } truelight@1320: break; truelight@0: } truelight@0: truelight@0: if (closeit) { truelight@0: i->prod_level = 0; ludde@2070: SetDParam(0, i->index); tron@2639: AddNewsItem( tron@2639: _industry_close_strings[i->type], tron@2639: NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_TILE, NT_ECONOMY, 0), tron@2639: i->xy + TileDiffXY(1, 1), 0 tron@2639: ); truelight@0: } truelight@0: } truelight@0: truelight@0: truelight@0: static void UpdateIndustryStatistics(Industry *i) truelight@0: { truelight@0: byte pct; truelight@201: tron@2469: if (i->produced_cargo[0] != CT_INVALID) { truelight@0: pct = 0; truelight@0: if (i->last_mo_production[0] != 0) { truelight@0: i->last_prod_year = _cur_year; truelight@0: pct = min(i->last_mo_transported[0] * 256 / i->last_mo_production[0],255); truelight@201: } truelight@0: i->pct_transported[0] = pct; truelight@0: truelight@0: i->total_production[0] = i->last_mo_production[0]; truelight@0: i->last_mo_production[0] = 0; truelight@0: truelight@0: i->total_transported[0] = i->last_mo_transported[0]; truelight@0: i->last_mo_transported[0] = 0; truelight@0: } truelight@0: tron@2469: if (i->produced_cargo[1] != CT_INVALID) { truelight@0: pct = 0; truelight@0: if (i->last_mo_production[1] != 0) { truelight@0: i->last_prod_year = _cur_year; truelight@0: pct = min(i->last_mo_transported[1] * 256 / i->last_mo_production[1],255); truelight@201: } truelight@0: i->pct_transported[1] = pct; truelight@0: truelight@0: i->total_production[1] = i->last_mo_production[1]; truelight@0: i->last_mo_production[1] = 0; truelight@0: truelight@0: i->total_transported[1] = i->last_mo_transported[1]; truelight@0: i->last_mo_transported[1] = 0; truelight@0: } truelight@0: truelight@0: tron@2469: if (i->produced_cargo[0] != CT_INVALID || i->produced_cargo[1] != CT_INVALID) truelight@919: InvalidateWindow(WC_INDUSTRY_VIEW, i->index); truelight@0: tron@2639: if (i->prod_level == 0) { truelight@0: DeleteIndustry(i); tron@2639: } else if (_patches.smooth_economy) { truelight@0: ExtChangeIndustryProduction(i); tron@2639: } truelight@0: } truelight@0: truelight@0: static const byte _new_industry_rand[4][32] = { truelight@0: {12,12,12,12,12,12,12, 0, 0, 6, 6, 9, 9, 3, 3, 3,18,18, 4, 4, 2, 2, 5, 5, 5, 5, 5, 5, 1, 1, 8, 8}, truelight@0: {16,16,16, 0, 0, 0, 9, 9, 9, 9,13,13, 3, 3, 3, 3,15,15,15, 4, 4,11,11,11,11,11,14,14, 1, 1, 7, 7}, truelight@0: {21,21,21,24,22,22,22,22,23,23,12,12,12, 4, 4,19,19,19,13,13,20,20,20,11,11,11,17,17,17,10,10,10}, truelight@0: {30,30,30,36,36,31,31,31,27,27,27,28,28,28,26,26,26,34,34,34,35,35,35,29,29,29,32,32,32,33,33,33}, truelight@0: }; truelight@0: truelight@0: static void MaybeNewIndustry(uint32 r) truelight@0: { truelight@0: int type; truelight@0: int j; truelight@0: Industry *i; truelight@0: tron@2140: type = _new_industry_rand[_opt.landscape][GB(r, 16, 5)]; truelight@0: tron@2639: if (type == IT_OIL_WELL && _date > 10958) return; tron@2639: if (type == IT_OIL_RIG && _date < 14610) return; truelight@0: truelight@0: j = 2000; tron@2639: for (;;) { tron@2637: i = CreateNewIndustry(RandomTile(), type); tron@2639: if (i != NULL) break; tron@2639: if (--j == 0) return; truelight@0: } truelight@0: tron@534: SetDParam(0, type + STR_4802_COAL_MINE); tron@534: SetDParam(1, i->town->index); tron@2260: AddNewsItem( tron@2260: (type != IT_FOREST) ? tron@2260: STR_482D_NEW_UNDER_CONSTRUCTION : STR_482E_NEW_BEING_PLANTED_NEAR, tron@2260: NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_TILE, NT_ECONOMY,0), i->xy, 0 tron@2260: ); truelight@0: } truelight@0: truelight@1320: static void ChangeIndustryProduction(Industry *i) truelight@0: { truelight@1320: bool only_decrease = false; truelight@1320: StringID str = STR_NULL; truelight@0: int type = i->type; truelight@201: truelight@1320: switch (_industry_close_mode[type]) { truelight@1320: case INDUSTRY_NOT_CLOSABLE: truelight@1320: return; truelight@0: truelight@1320: case INDUSTRY_PRODUCTION: truelight@1320: /* decrease or increase */ truelight@1320: if (type == IT_OIL_WELL && _opt.landscape == LT_NORMAL) truelight@1320: only_decrease = true; truelight@201: truelight@1320: if (only_decrease || CHANCE16(1,3)) { truelight@1320: /* If you transport > 60%, 66% chance we increase, else 33% chance we increase */ truelight@1320: if (!only_decrease && (i->pct_transported[0] > 153) != CHANCE16(1,3)) { truelight@1320: /* Increase production */ truelight@1320: if (i->prod_level != 0x80) { truelight@1320: byte b; truelight@201: truelight@1320: i->prod_level <<= 1; truelight@1320: truelight@1320: b = i->production_rate[0] * 2; truelight@1320: if (i->production_rate[0] >= 128) truelight@1320: b = 0xFF; truelight@1320: i->production_rate[0] = b; truelight@1320: truelight@1320: b = i->production_rate[1] * 2; truelight@1320: if (i->production_rate[1] >= 128) truelight@1320: b = 0xFF; truelight@1320: i->production_rate[1] = b; truelight@1320: truelight@1320: str = _industry_prod_up_strings[type]; truelight@1320: } truelight@1320: } else { truelight@1320: /* Decrease production */ truelight@1320: if (i->prod_level == 4) { truelight@1320: i->prod_level = 0; truelight@1320: str = _industry_close_strings[type]; truelight@1320: } else { truelight@1320: i->prod_level >>= 1; truelight@1320: i->production_rate[0] = (i->production_rate[0] + 1) >> 1; truelight@1320: i->production_rate[1] = (i->production_rate[1] + 1) >> 1; truelight@1320: truelight@1320: str = _industry_prod_down_strings[type]; truelight@1320: } truelight@0: } truelight@0: } truelight@1320: break; truelight@1320: truelight@1320: case INDUSTRY_CLOSABLE: truelight@1320: /* maybe close */ truelight@1320: if ( (byte)(_cur_year - i->last_prod_year) >= 5 && CHANCE16(1,2)) { truelight@1320: i->prod_level = 0; truelight@1320: str = _industry_close_strings[type]; truelight@1320: } truelight@1320: break; truelight@1320: } truelight@1320: truelight@1320: if (str != STR_NULL) { ludde@2070: SetDParam(0, i->index); tron@1981: AddNewsItem(str, NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_TILE, NT_ECONOMY, 0), i->xy + TileDiffXY(1, 1), 0); truelight@0: } truelight@0: } truelight@0: tron@1093: void IndustryMonthlyLoop(void) truelight@0: { truelight@0: Industry *i; tron@2498: PlayerID old_player = _current_player; darkvater@266: _current_player = OWNER_NONE; truelight@0: truelight@830: FOR_ALL_INDUSTRIES(i) { tron@2639: if (i->xy != 0) UpdateIndustryStatistics(i); truelight@0: } truelight@0: truelight@1267: /* 3% chance that we start a new industry */ truelight@1267: if (CHANCE16(3, 100)) { truelight@1267: MaybeNewIndustry(Random()); truelight@1269: } else if (!_patches.smooth_economy && _total_industries > 0) { truelight@1267: i = GetIndustry(RandomRange(_total_industries)); tron@2639: if (i->xy != 0) ChangeIndustryProduction(i); truelight@0: } darkvater@266: darkvater@266: _current_player = old_player; darkvater@266: truelight@0: // production-change truelight@0: _industry_sort_dirty = true; truelight@0: InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0); truelight@0: } truelight@0: truelight@0: tron@1093: void InitializeIndustries(void) truelight@0: { truelight@1267: CleanPool(&_industry_pool); truelight@1267: AddBlockToPool(&_industry_pool); truelight@919: truelight@0: _total_industries = 0; truelight@0: _industry_sort_dirty = true; truelight@0: } truelight@0: truelight@0: const TileTypeProcs _tile_type_industry_procs = { truelight@0: DrawTile_Industry, /* draw_tile_proc */ truelight@0: GetSlopeZ_Industry, /* get_slope_z_proc */ truelight@0: ClearTile_Industry, /* clear_tile_proc */ truelight@0: GetAcceptedCargo_Industry, /* get_accepted_cargo_proc */ truelight@0: GetTileDesc_Industry, /* get_tile_desc_proc */ truelight@0: GetTileTrackStatus_Industry,/* get_tile_track_status_proc */ truelight@0: ClickTile_Industry, /* click_tile_proc */ truelight@0: AnimateTile_Industry, /* animate_tile_proc */ truelight@0: TileLoop_Industry, /* tile_loop_proc */ truelight@0: ChangeTileOwner_Industry, /* change_tile_owner_proc */ truelight@0: GetProducedCargo_Industry, /* get_produced_cargo_proc */ truelight@0: NULL, /* vehicle_enter_tile_proc */ truelight@0: NULL, /* vehicle_leave_tile_proc */ dominik@39: GetSlopeTileh_Industry, /* get_slope_tileh_proc */ truelight@0: }; truelight@0: Darkvater@1881: static const SaveLoad _industry_desc[] = { tron@1174: SLE_CONDVAR(Industry, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), tron@1174: SLE_CONDVAR(Industry, xy, SLE_UINT32, 6, 255), truelight@0: SLE_VAR(Industry,width, SLE_UINT8), truelight@0: SLE_VAR(Industry,height, SLE_UINT8), truelight@0: SLE_REF(Industry,town, REF_TOWN), truelight@0: SLE_ARR(Industry,produced_cargo, SLE_UINT8, 2), truelight@0: SLE_ARR(Industry,cargo_waiting, SLE_UINT16, 2), truelight@0: SLE_ARR(Industry,production_rate, SLE_UINT8, 2), truelight@0: SLE_ARR(Industry,accepts_cargo, SLE_UINT8, 3), truelight@0: SLE_VAR(Industry,prod_level, SLE_UINT8), truelight@0: SLE_ARR(Industry,last_mo_production,SLE_UINT16, 2), truelight@0: SLE_ARR(Industry,last_mo_transported,SLE_UINT16, 2), truelight@0: SLE_ARR(Industry,pct_transported,SLE_UINT8, 2), truelight@0: SLE_ARR(Industry,total_production,SLE_UINT16, 2), truelight@0: SLE_ARR(Industry,total_transported,SLE_UINT16, 2), truelight@0: truelight@0: SLE_VAR(Industry,counter, SLE_UINT16), truelight@0: truelight@0: SLE_VAR(Industry,type, SLE_UINT8), truelight@0: SLE_VAR(Industry,owner, SLE_UINT8), truelight@0: SLE_VAR(Industry,color_map, SLE_UINT8), truelight@0: SLE_VAR(Industry,last_prod_year, SLE_UINT8), truelight@0: SLE_VAR(Industry,was_cargo_delivered,SLE_UINT8), truelight@0: truelight@0: // reserve extra space in savegame here. (currently 32 bytes) truelight@0: SLE_CONDARR(NullStruct,null,SLE_FILE_U64 | SLE_VAR_NULL, 4, 2, 255), truelight@0: truelight@0: SLE_END() truelight@0: }; truelight@0: tron@1093: static void Save_INDY(void) truelight@0: { truelight@0: Industry *ind; truelight@919: truelight@0: // Write the vehicles truelight@830: FOR_ALL_INDUSTRIES(ind) { truelight@0: if (ind->xy != 0) { truelight@919: SlSetArrayIndex(ind->index); truelight@0: SlObject(ind, _industry_desc); truelight@0: } truelight@0: } truelight@0: } truelight@0: tron@1093: static void Load_INDY(void) truelight@0: { truelight@0: int index; truelight@1267: truelight@0: _total_industries = 0; truelight@1267: truelight@0: while ((index = SlIterateArray()) != -1) { truelight@1267: Industry *i; truelight@919: truelight@1267: if (!AddBlockIfNeeded(&_industry_pool, index)) truelight@1267: error("Industries: failed loading savegame: too many industries"); truelight@1267: truelight@1267: i = GetIndustry(index); truelight@919: SlObject(i, _industry_desc); truelight@1267: tron@2639: if (index > _total_industries) _total_industries = index; truelight@0: } truelight@0: } truelight@0: truelight@0: const ChunkHandler _industry_chunk_handlers[] = { truelight@0: { 'INDY', Save_INDY, Load_INDY, CH_ARRAY | CH_LAST}, truelight@0: };