truelight@0: #include "stdafx.h" truelight@0: #include "ttd.h" tron@507: #include "table/strings.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" 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: */ truelight@1267: void IndustryPoolNewBlock(uint start_item) truelight@1267: { truelight@1267: Industry *i; truelight@1267: truelight@1267: FOR_ALL_INDUSTRIES_FROM(i, start_item) truelight@1267: 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: truelight@0: byte _industry_sound_ctr; truelight@0: TileIndex _industry_sound_tile; truelight@0: truelight@0: void ShowIndustryViewWindow(int industry); truelight@0: void BuildOilRig(uint tile); truelight@0: void DeleteOilRig(uint tile); truelight@0: truelight@0: typedef struct DrawIndustryTileStruct { truelight@0: uint32 sprite_1; truelight@0: uint32 sprite_2; truelight@0: truelight@0: byte subtile_xy; truelight@0: byte width_height; 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: truelight@0: truelight@0: #include "table/industry_land.h" truelight@0: 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 { truelight@0: 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: 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, truelight@0: STR_4832_ANNOUNCES_IMMINENT_CLOSURE , truelight@0: }; truelight@0: truelight@0: truelight@0: static void IndustryDrawTileProc1(TileInfo *ti) truelight@0: { truelight@0: const DrawIndustrySpec1Struct *d; truelight@0: uint32 image; truelight@0: truelight@0: if (!(_map_owner[ti->tile] & 0x80)) truelight@0: return; truelight@201: truelight@0: d = &_draw_industry_spec1[_map3_lo[ti->tile]]; truelight@0: truelight@0: AddChildSpriteScreen(0x12A7 + d->image_1, d->x, 0); truelight@0: truelight@0: if ( (image = d->image_2) != 0) truelight@0: AddChildSpriteScreen(0x12B0 + image - 1, 8, 41); truelight@0: truelight@0: if ( (image = d->image_3) != 0) truelight@201: AddChildSpriteScreen(0x12AC + image - 1, truelight@0: _drawtile_proc1_x[image-1], _drawtile_proc1_y[image-1]); truelight@0: } truelight@0: truelight@0: static void IndustryDrawTileProc2(TileInfo *ti) truelight@0: { truelight@0: int x = 0; truelight@201: truelight@0: if (_map_owner[ti->tile] & 0x80) { truelight@0: x = _industry_anim_offs[_map3_lo[ti->tile]]; truelight@0: if ( (byte)x == 0xFF) truelight@0: x = 0; truelight@0: } truelight@0: truelight@0: AddChildSpriteScreen(0x129F, 22-x, x+24); truelight@0: AddChildSpriteScreen(0x129E, 6, 0xE); truelight@0: } truelight@0: truelight@0: static void IndustryDrawTileProc3(TileInfo *ti) truelight@0: { truelight@0: if (_map_owner[ti->tile] & 0x80) { truelight@201: AddChildSpriteScreen(0x128B, 5, truelight@0: _industry_anim_offs_2[_map3_lo[ti->tile]]); truelight@0: } darkvater@552: AddChildSpriteScreen(4746, 3, 67); truelight@0: } truelight@0: truelight@0: static void IndustryDrawTileProc4(TileInfo *ti) truelight@0: { truelight@0: const DrawIndustrySpec4Struct *d; truelight@0: truelight@0: d = &_industry_anim_offs_3[_map3_lo[ti->tile]]; 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) { truelight@0: 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: truelight@0: static void DrawCoalPlantSparkles(TileInfo *ti) truelight@0: { truelight@0: int image = _map_owner[ti->tile]; truelight@0: if (image & 0x80) { truelight@0: image = (image >> 2) & 0x1F; truelight@0: if (image != 0 && image < 7) { truelight@201: AddChildSpriteScreen(image + 0x806, truelight@0: _coal_plant_sparkles_x[image-1], truelight@0: _coal_plant_sparkles_y[image-1] truelight@0: ); truelight@0: } truelight@0: } truelight@0: } truelight@0: truelight@0: typedef void IndustryDrawTileProc(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: { truelight@0: Industry *ind; truelight@0: const DrawIndustryTileStruct *dits; truelight@0: byte z; truelight@0: uint32 image, ormod; truelight@0: truelight@0: /* Pointer to industry */ truelight@919: ind = GetIndustry(_map2[ti->tile]); truelight@0: ormod = (ind->color_map+0x307)<<16; truelight@0: truelight@0: /* Retrieve pointer to the draw industry tile struct */ truelight@0: dits = &_industry_draw_tile_data[(ti->map5<<2) | (_map_owner[ti->tile]&3)]; truelight@0: truelight@0: image = dits->sprite_1; truelight@0: if (image&0x8000 && (image & 0xFFFF0000) == 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) { truelight@0: AddSortableSpriteToDraw((ti->tileh & 0xF) + 0x3DD, 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? */ truelight@0: if ((image = dits->sprite_2) != 0) { truelight@0: truelight@0: if (image&0x8000 && (image & 0xFFFF0000) == 0) truelight@0: image |= ormod; truelight@201: tron@497: if (_display_opt & DO_TRANS_BUILDINGS) truelight@0: image = (image & 0x3FFF) | 0x3224000; truelight@201: truelight@201: AddSortableSpriteToDraw(image, truelight@0: ti->x | (dits->subtile_xy>>4), truelight@0: ti->y | (dits->subtile_xy&0xF), truelight@0: (dits->width_height>>4)+1, truelight@0: (dits->width_height&0xF)+1, truelight@0: dits->dz, truelight@0: z); truelight@0: tron@497: if (_display_opt & DO_TRANS_BUILDINGS) truelight@0: return; truelight@0: } truelight@0: truelight@201: /* TTDBUG: strange code here, return if AddSortableSpriteToDraw failed? */ truelight@0: { truelight@0: int proc; truelight@0: if ((proc=dits->proc-1) >= 0 ) truelight@0: _industry_draw_tile_procs[proc](ti); truelight@0: } truelight@0: } truelight@0: truelight@0: truelight@0: static uint GetSlopeZ_Industry(TileInfo *ti) { truelight@0: return GetPartialZ(ti->x&0xF, ti->y&0xF, ti->tileh) + ti->z; truelight@0: } truelight@0: dominik@39: static uint GetSlopeTileh_Industry(TileInfo *ti) { dominik@39: return 0; dominik@39: } dominik@39: tron@473: static void GetAcceptedCargo_Industry(uint tile, AcceptedCargo ac) truelight@0: { truelight@0: int m5 = _map5[tile]; truelight@0: int a; truelight@0: truelight@0: a = _industry_map5_accepts_1[m5]; tron@473: if (a >= 0) ac[a] = (a == 0) ? 1 : 8; truelight@0: truelight@0: a = _industry_map5_accepts_2[m5]; tron@473: if (a >= 0) ac[a] = 8; truelight@0: truelight@0: a = _industry_map5_accepts_3[m5]; tron@473: if (a >= 0) ac[a] = 8; truelight@0: } truelight@0: truelight@0: static void GetTileDesc_Industry(uint tile, TileDesc *td) truelight@0: { truelight@919: Industry *i = GetIndustry(_map2[tile]); truelight@0: truelight@0: td->owner = i->owner; truelight@0: td->str = STR_4802_COAL_MINE + i->type; truelight@0: if ((_map_owner[tile] & 0x80) == 0) { tron@534: SetDParamX(td->dparam, 0, td->str); truelight@0: td->str = STR_2058_UNDER_CONSTRUCTION; truelight@0: } truelight@0: } truelight@0: truelight@0: static int32 ClearTile_Industry(uint tile, byte flags) truelight@0: { truelight@919: Industry *i = GetIndustry(_map2[tile]); 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: truelight@0: if (flags & DC_EXEC) { truelight@0: DeleteIndustry(i); truelight@0: } 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@410: static void TransportIndustryGoods(uint tile) truelight@0: { truelight@0: Industry *i; truelight@0: int type; truelight@0: uint cw, am; truelight@0: byte m5; truelight@0: truelight@919: i = GetIndustry(_map2[tile]); truelight@201: truelight@0: type = i->type; truelight@0: cw = min(i->cargo_waiting[0], 255); truelight@0: if (cw > _industry_min_cargo[type]/* && i->produced_cargo[0] != 0xFF*/) { truelight@0: i->cargo_waiting[0] -= cw; truelight@0: truelight@0: /* fluctuating economy? */ truelight@0: if (_economy.fluct <= 0) cw = (cw + 1) >> 1; 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; truelight@0: if (am != 0 && (m5 = _industry_produce_map5[_map5[tile]]) != 0xFF) { truelight@0: _map5[tile] = m5; truelight@0: _map_owner[tile] = 0x80; truelight@0: MarkTileDirtyByTile(tile); truelight@0: } truelight@0: } truelight@0: truelight@0: type = i->type; truelight@0: cw = min(i->cargo_waiting[1], 255); truelight@0: if (cw > _industry_min_cargo[type]) { truelight@0: i->cargo_waiting[1] -= cw; truelight@201: truelight@0: if (_economy.fluct <= 0) cw = (cw + 1) >> 1; 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: truelight@0: static void AnimateTile_Industry(uint tile) truelight@0: { truelight@0: byte m,n; truelight@0: truelight@0: switch(_map5[tile]) { truelight@0: case 174: truelight@0: if ((_tick_counter & 1) == 0) { truelight@0: m = _map3_lo[tile] + 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: } truelight@0: _map3_lo[tile] = 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) { truelight@0: m = _map3_lo[tile]; 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: } truelight@0: _map3_lo[tile] = 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) { truelight@0: m = _map3_lo[tile]; truelight@0: truelight@0: if (++m >= 40) { truelight@0: m = 0; truelight@0: DeleteAnimatedTile(tile); truelight@0: } truelight@0: _map3_lo[tile] = 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) { truelight@0: m = _map_owner[tile]; truelight@0: if ((m & (31<<2)) == (6 << 2)) { truelight@0: _map_owner[tile] = m&~(31<<2); truelight@0: DeleteAnimatedTile(tile); truelight@0: } else { truelight@0: _map_owner[tile] = 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) { truelight@0: m = _map3_lo[tile] + 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: truelight@0: if (m >= 50 && (m=0,++_map3_hi[tile] >= 8)) { truelight@0: _map3_hi[tile] = 0; truelight@0: DeleteAnimatedTile(tile); truelight@0: } truelight@201: _map3_lo[tile] = 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) { truelight@0: m = _map5[tile] + 1; truelight@0: if (m == 155+1) m = 148; truelight@0: _map5[tile] = 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); truelight@0: m = _map_owner[tile]; truelight@0: m = (m & 3) + 1; truelight@0: n = _map5[tile]; truelight@0: if (m == 4 && (m=0,++n) == 32+1 && (n=30,b)) { truelight@0: _map_owner[tile] = 0x83; truelight@0: _map5[tile] = 29; truelight@201: DeleteAnimatedTile(tile); truelight@0: } else { truelight@0: _map5[tile] = n; truelight@0: _map_owner[tile] = (_map_owner[tile] & ~3) | m; 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) { truelight@0: if (! (_map_owner[tile] & 0x40)) { truelight@0: _map_owner[tile] |= 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: } truelight@0: m = (_map_owner[tile] + 1) | 0x40; truelight@0: if (m > 0xC2) m = 0xC0; truelight@0: _map_owner[tile] = 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: truelight@0: m = (_map_owner[tile] & 0xBF) - 1; truelight@0: if (m < 0x80) m = 0x82; truelight@0: _map_owner[tile] = m; truelight@0: MarkTileDirtyByTile(tile); truelight@0: } truelight@0: } break; truelight@0: } truelight@0: } truelight@0: truelight@0: static void MakeIndustryTileBiggerCase8(uint 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: truelight@0: static void MakeIndustryTileBigger(uint tile, byte size) truelight@0: { truelight@0: byte b = (byte)((size + (1<<2)) & (3<<2)); truelight@0: truelight@0: if (b != 0) { truelight@0: _map_owner[tile] = b | (size & 3); truelight@0: return; truelight@0: } truelight@0: truelight@0: size = (size + 1) & 3; truelight@0: if (size == 3) size |= 0x80; truelight@0: _map_owner[tile] = size | b; truelight@201: truelight@0: MarkTileDirtyByTile(tile); truelight@0: truelight@0: if (!(_map_owner[tile] & 0x80)) truelight@0: return; truelight@0: truelight@0: switch(_map5[tile]) { truelight@0: case 8: truelight@0: MakeIndustryTileBiggerCase8(tile); truelight@0: break; truelight@0: truelight@0: case 24: truelight@0: if (_map5[tile + TILE_XY(0,1)] == 24) { truelight@0: BuildOilRig(tile); truelight@0: } truelight@0: break; truelight@0: truelight@0: case 143: truelight@0: case 162: truelight@0: case 165: truelight@0: _map3_lo[tile] = 0; truelight@0: _map3_hi[tile] = 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: truelight@0: truelight@0: static void TileLoopIndustryCase161(uint 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: truelight@0: if (v != NULL) truelight@0: v->u.special.unk2 = dir; truelight@0: } truelight@0: truelight@0: static void TileLoop_Industry(uint tile) truelight@0: { truelight@0: byte n; truelight@0: truelight@0: if (!(_map_owner[tile] & 0x80)) { truelight@0: MakeIndustryTileBigger(tile, _map_owner[tile]); truelight@0: return; truelight@0: } truelight@0: truelight@0: if (_game_mode == GM_EDITOR) truelight@0: return; truelight@0: truelight@0: TransportIndustryGoods(tile); truelight@0: truelight@0: n = _industry_map5_animation_next[_map5[tile]]; truelight@0: if (n != 255) { truelight@0: _map5[tile] = n; truelight@0: _map_owner[tile] = 0; truelight@0: MarkTileDirtyByTile(tile); truelight@0: return; truelight@0: } truelight@0: truelight@0: #define SET_AND_ANIMATE(tile,a,b) { _map5[tile]=a; _map_owner[tile]=b; AddAnimatedTile(tile); } truelight@0: #define SET_AND_UNANIMATE(tile,a,b) { _map5[tile]=a; _map_owner[tile]=b; DeleteAnimatedTile(tile); } truelight@0: truelight@0: switch(_map5[tile]) { 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: truelight@0: case 49: { tron@1359: CreateEffectVehicleAbove(TileX(tile) * 16 + 6, TileY(tile) * 16 + 6, 43, EV_SMOKE); truelight@0: } break; truelight@0: truelight@0: truelight@0: case 143: { truelight@919: Industry *i = GetIndustry(_map2[tile]); truelight@0: if (i->was_cargo_delivered) { truelight@0: i->was_cargo_delivered = false; truelight@0: if ((_map3_hi[tile]|_map3_lo[tile]) != 0) truelight@0: _map3_hi[tile] = 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: truelight@0: if (CHANCE16(1,3)) { truelight@0: AddAnimatedTile(tile); truelight@0: } truelight@0: break; truelight@0: } truelight@0: } truelight@0: truelight@0: truelight@0: static void ClickTile_Industry(uint tile) truelight@0: { truelight@0: ShowIndustryViewWindow(_map2[tile]); truelight@0: } truelight@0: truelight@159: static uint32 GetTileTrackStatus_Industry(uint tile, TransportType mode) truelight@0: { truelight@0: return 0; truelight@0: } truelight@0: truelight@0: static void GetProducedCargo_Industry(uint tile, byte *b) truelight@0: { truelight@919: Industry *i = GetIndustry(_map2[tile]); truelight@0: b[0] = i->produced_cargo[0]; truelight@0: b[1] = i->produced_cargo[1]; truelight@0: } truelight@0: truelight@0: static void ChangeTileOwner_Industry(uint tile, byte old_player, byte 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)) { truelight@919: if (_map2[tile_cur] == i->index) { truelight@0: DoClearSquare(tile_cur); truelight@0: } tron@1035: } else if (IsTileType(tile_cur, MP_STATION) && _map5[tile_cur] == 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@1048: byte m5 = _map5[tile] & 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@1048: byte m5 = _map5[tile] & 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: truelight@0: static void SetupFarmFieldFence(uint 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; truelight@0: if (or == 1 && (uint16)Random() <= 9362) 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: } truelight@0: _map3_hi[tile] = (_map3_hi[tile] & and) | or; truelight@0: } truelight@201: truelight@0: tile += direction ? TILE_XY(0,1) : TILE_XY(1,0); truelight@0: } while (--size); truelight@0: } truelight@0: truelight@0: static void PlantFarmField(uint tile) truelight@0: { truelight@0: uint size_x, size_y; truelight@0: uint32 r; truelight@0: int 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; truelight@0: size_x = (byte)r; truelight@0: size_y = r >> 8; truelight@0: truelight@0: /* offset tile to match size */ truelight@0: tile = tile - TILE_XY(size_x>>1, size_y>>1); 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) truelight@0: if ((uint)(count * 2) >= size_x * size_y) truelight@0: return; truelight@0: truelight@0: /* determine type of field */ truelight@0: r = Random(); truelight@0: type = ((r & 0xE0) | 0xF); truelight@0: type2 = ((byte)(r >> 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: truelight@0: SetupFarmFieldFence(tile-TILE_XY(1,0), size_y, type, 1); truelight@0: SetupFarmFieldFence(tile-TILE_XY(0,1), size_x, type, 0); truelight@0: SetupFarmFieldFence(tile+TILE_XY(1,0) * (size_x-1), size_y, type, 1); truelight@0: SetupFarmFieldFence(tile+TILE_XY(0,1) * (size_y-1), size_x, type, 0); truelight@0: } truelight@0: truelight@0: static void MaybePlantFarmField(Industry *i) truelight@0: { truelight@0: uint tile; truelight@0: if (CHANCE16(1,8)) { truelight@543: int x = (i->width>>1) + Random() % 31 - 16; truelight@543: int y = (i->height>>1) + Random() % 31 - 16; truelight@543: tile = TileAddWrap(i->xy, x, y); matthijs@1247: if (tile != INVALID_TILE) truelight@0: 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: truelight@0: uint tile = i->xy; truelight@0: int dir, a, j; truelight@0: truelight@0: if ((_map_owner[tile] & 0x80) == 0) truelight@0: return; truelight@0: truelight@0: /* search outwards as a rectangular spiral */ truelight@0: for(a=1; a!=41; a+=2) { truelight@0: for(dir=0; dir!=4; dir++) { truelight@0: j = a; truelight@0: do { truelight@0: tile = TILE_MASK(tile); tron@1035: if (IsTileType(tile, MP_TREES)) { truelight@314: uint 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: } truelight@0: tile -= TILE_XY(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: truelight@0: if (i->type == IT_FARM) truelight@0: MaybePlantFarmField(i); truelight@0: else if (i->type == IT_LUMBER_MILL && (i->counter & 0x1FF) == 0) truelight@0: ChopLumberMillTrees(i); 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: truelight@0: if (_game_mode == GM_EDITOR) truelight@0: return; truelight@0: truelight@830: FOR_ALL_INDUSTRIES(i) { truelight@0: if (i->xy != 0) truelight@0: ProduceIndustryGoods(i); truelight@0: } truelight@0: } truelight@0: truelight@0: truelight@0: static bool CheckNewIndustry_NULL(uint tile, int type) truelight@0: { truelight@0: return true; truelight@0: } truelight@0: truelight@0: static bool CheckNewIndustry_Forest(uint 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: truelight@0: static bool CheckNewIndustry_Oilwell(uint tile, int type) truelight@0: { truelight@0: int x,y; truelight@201: dominik@7: if(_ignore_restrictions && _game_mode == GM_EDITOR) dominik@7: return true; dominik@7: truelight@0: if (type != IT_OIL_RIG && _game_mode == GM_EDITOR) truelight@0: return true; truelight@0: tron@926: x = TileX(tile); tron@926: y = TileY(tile); truelight@0: truelight@0: if ( x < 15 || y < 15 || x > 238 || y > 238) truelight@0: return true; truelight@0: truelight@0: _error_message = STR_483B_CAN_ONLY_BE_POSITIONED; truelight@0: return false; truelight@0: } truelight@0: truelight@0: static bool CheckNewIndustry_Farm(uint 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: truelight@0: static bool CheckNewIndustry_Plantation(uint 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: truelight@0: static bool CheckNewIndustry_Water(uint 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: truelight@0: static bool CheckNewIndustry_Lumbermill(uint 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: truelight@0: static bool CheckNewIndustry_BubbleGen(uint tile, int type) truelight@0: { truelight@0: if (GetTileZ(tile) > 32) { truelight@0: return false; truelight@0: } truelight@0: return true; truelight@0: } truelight@0: truelight@0: typedef bool CheckNewIndustryProc(uint tile, int type); truelight@0: static CheckNewIndustryProc * const _check_new_industry_procs[] = { truelight@0: CheckNewIndustry_NULL, truelight@0: CheckNewIndustry_Forest, truelight@0: CheckNewIndustry_Oilwell, truelight@0: CheckNewIndustry_Farm, truelight@0: CheckNewIndustry_Plantation, truelight@0: CheckNewIndustry_Water, truelight@0: CheckNewIndustry_Lumbermill, truelight@0: CheckNewIndustry_BubbleGen, truelight@0: }; truelight@0: truelight@0: static bool CheckSuitableIndustryPos(uint tile) truelight@0: { tron@926: uint x = TileX(tile); tron@926: uint y = TileY(tile); truelight@0: tron@856: 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: truelight@0: static Town *CheckMultipleIndustryInTown(uint tile, int type) truelight@0: { truelight@0: Town *t; truelight@0: Industry *i; truelight@0: truelight@0: t = ClosestTownFromTile(tile, (uint)-1); truelight@201: truelight@0: if (_patches.multiple_industry_per_town) truelight@0: 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: truelight@0: static bool CheckIfIndustryTilesAreFree(uint tile, const IndustryTileTable *it, int type, Town *t) truelight@0: { truelight@0: TileInfo ti; truelight@0: uint cur_tile; truelight@0: truelight@0: _error_message = STR_0239_SITE_UNSUITABLE; truelight@0: truelight@0: do { tron@909: cur_tile = tile + ToTileIndexDiff(it->ti); truelight@0: if (!IsValidTile(cur_tile)) { truelight@0: if (it->map5 == 0xff) truelight@0: continue; truelight@0: return false; truelight@0: } truelight@201: truelight@0: FindLandscapeHeightByTile(&ti, cur_tile); truelight@201: truelight@0: if (it->map5 == 0xFF) { truelight@0: if (ti.type != MP_WATER || ti.tileh != 0) truelight@0: return false; truelight@0: } else { truelight@0: if (!EnsureNoVehicle(cur_tile)) truelight@0: return false; truelight@0: truelight@0: if (type == IT_OIL_RIG) { truelight@0: if (ti.type != MP_WATER || ti.map5 != 0) truelight@0: return false; truelight@0: } else { truelight@0: if (ti.type == MP_WATER && ti.map5 == 0) truelight@0: return false; truelight@0: if (ti.tileh & 0x10) 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: truelight@0: if (bits & 0x10) truelight@0: return false; truelight@201: truelight@0: t = ~ti.tileh; truelight@0: truelight@0: if (bits & 1 && (t & (1+8))) truelight@0: return false; truelight@0: truelight@0: if (bits & 2 && (t & (4+8))) truelight@0: return false; truelight@0: truelight@0: if (bits & 4 && (t & (1+2))) truelight@0: return false; truelight@0: truelight@0: if (bits & 8 && (t & (2+4))) truelight@0: 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@1245: if (DistanceMax(t->xy, cur_tile) > 9) truelight@0: 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: truelight@0: if (DoCommandByTile(cur_tile, 0, 0, DC_AUTO, CMD_LANDSCAPE_CLEAR) == CMD_ERROR) 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: truelight@0: static bool CheckIfTooCloseToIndustry(uint tile, int type) truelight@0: { truelight@0: Industry *i; truelight@0: const IndustrySpec *spec; truelight@0: spec = &_industry_spec[type]; truelight@0: truelight@0: // accepting industries won't be close, not even with patch truelight@0: if (_patches.same_industry_close && (spec->accepts_cargo[0] == 0xFF) ) 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@1245: (DistanceMax(tile, i->xy) <= 14) && truelight@0: spec->accepts_cargo[0] != 0xFF && tron@1019: spec->accepts_cargo[0] == i->accepts_cargo[0] && tron@1019: !(_game_mode == GM_EDITOR && miham@952: _patches.same_industry_close && miham@952: _patches.multiple_industry_per_town)) { truelight@0: _error_message = STR_INDUSTRY_TOO_CLOSE; truelight@0: return false; truelight@0: } 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: truelight@919: if (i->index > _total_industries) truelight@919: _total_industries = i->index; truelight@919: truelight@1267: memset(i, 0, sizeof(Industry)); 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 */ truelight@1267: if (AddBlockToPool(&_industry_pool)) truelight@1267: return AllocateIndustry(); truelight@1267: truelight@0: return NULL; truelight@0: } truelight@0: truelight@0: static void DoCreateNewIndustry(Industry *i, uint tile, int type, const IndustryTileTable *it, Town *t, byte owner) truelight@0: { truelight@0: const IndustrySpec *spec; truelight@0: uint32 r; truelight@0: uint cur_tile; 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: truelight@0: r = Random() & 0xFFF; truelight@0: i->color_map = (byte)(r >> 8); truelight@0: i->counter = (uint16)r; 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: truelight@0: if (_generating_world == 0) truelight@0: i->total_production[0] = i->total_production[1] = 0; truelight@201: truelight@0: i->prod_level = 0x10; truelight@0: truelight@0: do { tron@909: 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); truelight@0: _map5[cur_tile] = it->map5; truelight@919: _map2[cur_tile] = i->index; truelight@0: _map_owner[cur_tile] = _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) { truelight@0: tile = i->xy + TILE_XY((i->width >> 1), (i->height >> 1)); truelight@0: for(j=0; j!=50; j++) { truelight@543: int x = Random() % 31 - 16; truelight@543: int y = Random() % 31 - 16; truelight@543: uint new_tile = TileAddWrap(tile, x, y); matthijs@1247: if (new_tile != INVALID_TILE) truelight@0: PlantFarmField(new_tile); truelight@131: } truelight@0: } truelight@0: _industry_sort_dirty = true; truelight@0: InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0); truelight@0: } truelight@0: truelight@0: /* p1 = industry type 0-36 */ truelight@0: int32 CmdBuildIndustry(int x, int y, uint32 flags, uint32 p1, uint32 p2) truelight@0: { truelight@0: uint tile = TILE_FROM_XY(x,y); truelight@0: Town *t; truelight@0: int num; truelight@0: const IndustryTileTable * const *itt; truelight@0: const IndustryTileTable *it; truelight@0: Industry *i; truelight@0: const IndustrySpec *spec; truelight@0: truelight@0: SET_EXPENSES_TYPE(EXPENSES_OTHER); truelight@0: truelight@0: if (!CheckSuitableIndustryPos(tile)) truelight@0: return CMD_ERROR; truelight@0: truelight@0: spec = &_industry_spec[p1]; truelight@0: truelight@0: if (!_check_new_industry_procs[spec->check_proc](tile, p1)) truelight@0: return CMD_ERROR; truelight@0: truelight@0: if ((t=CheckMultipleIndustryInTown(tile, p1)) == NULL) truelight@0: return CMD_ERROR; truelight@201: truelight@0: num = spec->num_table; truelight@0: itt = spec->table; truelight@0: truelight@0: do { truelight@0: if (--num < 0) truelight@0: return_cmd_error(STR_0239_SITE_UNSUITABLE); truelight@0: } while (!CheckIfIndustryTilesAreFree(tile, it=itt[num], p1, t)); truelight@0: truelight@0: truelight@0: if (!CheckIfTooCloseToIndustry(tile, p1)) truelight@0: return CMD_ERROR; truelight@0: truelight@0: if ( (i = AllocateIndustry()) == NULL) truelight@0: return CMD_ERROR; truelight@0: truelight@0: if (flags & DC_EXEC) truelight@0: DoCreateNewIndustry(i, tile, p1, it, t, 0x10); truelight@201: truelight@0: return (_price.build_industry >> 5) * _industry_type_costs[p1]; truelight@0: } truelight@0: truelight@0: truelight@0: Industry *CreateNewIndustry(uint tile, int type) truelight@0: { truelight@0: Town *t; truelight@0: const IndustryTileTable *it; truelight@0: Industry *i; truelight@0: truelight@0: const IndustrySpec *spec; truelight@0: truelight@0: if (!CheckSuitableIndustryPos(tile)) truelight@0: return NULL; truelight@0: truelight@0: spec = &_industry_spec[type]; truelight@0: truelight@0: if (!_check_new_industry_procs[spec->check_proc](tile, type)) truelight@0: return NULL; truelight@0: truelight@0: if (!(t=CheckMultipleIndustryInTown(tile, type))) truelight@0: return NULL; truelight@0: truelight@0: /* pick a random layout */ truelight@0: it = spec->table[(spec->num_table * (uint16)Random()) >> 16]; truelight@0: truelight@0: if (!CheckIfIndustryTilesAreFree(tile, it, type, t)) truelight@0: return NULL; truelight@0: truelight@0: if (!CheckIfTooCloseToIndustry(tile, type)) truelight@0: return NULL; truelight@0: truelight@0: if ( (i = AllocateIndustry()) == NULL) truelight@0: return NULL; truelight@0: truelight@0: DoCreateNewIndustry(i, tile, type, it, t, 0x10); 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: { tron@1202: int num = tron@1202: ScaleByMapSize(_numof_industry_table[_opt.diff.number_industries][amount]); truelight@110: truelight@110: if (_opt.diff.number_industries != 0) orudge@61: { darkvater@266: byte old_player = _current_player; darkvater@266: _current_player = OWNER_NONE; orudge@61: assert(num > 0); truelight@0: truelight@0: do { orudge@61: int i = 2000; orudge@61: do { orudge@61: if (CreateNewIndustry(TILE_MASK(Random()), type) != NULL) truelight@201: break; orudge@61: } while (--i != 0); 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: truelight@1320: 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 */ truelight@1320: for (j=0; j != 2 && i->produced_cargo[j]!=255; j++){ truelight@1320: uint32 r; truelight@1320: int change,percent,old; truelight@1320: int mag; truelight@1320: truelight@1320: change = old = i->production_rate[j]; truelight@1320: if (CHANCE16R(20,1024,r))change -= ((RandomRange(50) + 10)*old) >> 8; truelight@1320: if (CHANCE16I(20+(i->pct_transported[j]*20>>8),1024,r>>16)) change += ((RandomRange(50) + 10)*old) >> 8; truelight@1320: truelight@1320: // make sure it doesn't exceed 255 or goes below 0 truelight@1320: change = clamp(change, 0, 255); truelight@1320: if (change == old) { truelight@1320: closeit = false; truelight@1320: continue; truelight@1320: } truelight@1320: truelight@1320: percent = change*100/old - 100; truelight@1320: i->production_rate[j] = change; truelight@1320: truelight@1320: if (change >= _industry_spec[i->type].production_rate[j]/4) truelight@1320: closeit = false; truelight@1320: truelight@1320: mag = abs(percent); truelight@1320: if (mag >= 10) { truelight@1320: SetDParam(3, mag); truelight@1320: SetDParam(0,_cargoc.names_s[i->produced_cargo[j]]); truelight@1320: SetDParam(1, i->town->index); truelight@1320: SetDParam(2, i->type + STR_4802_COAL_MINE); truelight@1320: AddNewsItem(percent>=0 ? STR_INDUSTRY_PROD_GOUP : STR_INDUSTRY_PROD_GODOWN, truelight@1320: NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_TILE, NT_ECONOMY, 0), truelight@1320: i->xy + TILE_XY(1,1), 0); truelight@1320: } truelight@0: } truelight@1320: break; truelight@0: } truelight@0: truelight@0: if (closeit) { truelight@0: i->prod_level = 0; tron@534: SetDParam(1, i->type + STR_4802_COAL_MINE); tron@534: SetDParam(0, i->town->index); truelight@0: AddNewsItem(_industry_close_strings[i->type], NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_TILE, NT_ECONOMY, 0), i->xy + TILE_XY(1,1), 0); truelight@0: } truelight@0: } truelight@0: truelight@0: truelight@0: static void UpdateIndustryStatistics(Industry *i) truelight@0: { truelight@0: byte pct; truelight@201: truelight@201: if (i->produced_cargo[0] != 0xFF) { 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: truelight@0: if (i->produced_cargo[1] != 0xFF) { 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: truelight@0: if ( i->produced_cargo[0] != 0xFF || i->produced_cargo[1] != 0xFF ) truelight@919: InvalidateWindow(WC_INDUSTRY_VIEW, i->index); truelight@0: truelight@0: if (i->prod_level == 0) truelight@0: DeleteIndustry(i); truelight@0: else if (_patches.smooth_economy) truelight@0: ExtChangeIndustryProduction(i); 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: truelight@0: type = _new_industry_rand[_opt.landscape][(r >> 16) & 0x1F]; truelight@0: if (type == IT_OIL_WELL && _date > 10958) truelight@0: return; truelight@0: truelight@0: if (type == IT_OIL_RIG && _date < 14610) truelight@0: return; truelight@0: truelight@0: j = 2000; truelight@0: for(;;) { truelight@0: i = CreateNewIndustry(TILE_MASK(Random()), type); truelight@0: if (i != NULL) truelight@0: break; truelight@0: if (--j == 0) truelight@0: return; truelight@0: } truelight@0: tron@534: SetDParam(0, type + STR_4802_COAL_MINE); tron@534: SetDParam(1, i->town->index); truelight@0: AddNewsItem( STR_482D_NEW_UNDER_CONSTRUCTION + (type == IT_FOREST), NEWS_FLAGS(NM_THIN,NF_VIEWPORT|NF_TILE,NT_ECONOMY,0), i->xy, 0); 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) { truelight@1320: SetDParam(1, type + STR_4802_COAL_MINE); truelight@1320: SetDParam(0, i->town->index); truelight@1320: AddNewsItem(str, NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_TILE, NT_ECONOMY, 0), i->xy + TILE_XY(1,1), 0); truelight@0: } truelight@0: } truelight@0: tron@1093: void IndustryMonthlyLoop(void) truelight@0: { truelight@0: Industry *i; darkvater@266: byte old_player = _current_player; darkvater@266: _current_player = OWNER_NONE; truelight@0: truelight@830: FOR_ALL_INDUSTRIES(i) { truelight@0: if (i->xy != 0) truelight@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)); truelight@1270: if (i->xy != 0) truelight@1320: 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@919: 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: truelight@0: static const byte _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: truelight@1267: if (index > _total_industries) truelight@1267: _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: }; truelight@0: