tron@2186: /* $Id$ */ tron@2186: truelight@0: #include "stdafx.h" Darkvater@1891: #include "openttd.h" tron@3144: #include "clear_map.h" truelight@4356: #include "functions.h" tron@3314: #include "industry_map.h" tron@3338: #include "station_map.h" tron@507: #include "table/strings.h" celestar@2148: #include "table/sprites.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" belugas@3654: #include "table/industry_land.h" belugas@3654: #include "table/build_industry.h" truelight@4300: #include "genworld.h" rubidium@4261: #include "date.h" belugas@5056: #include "water_map.h" truelight@0: truelight@4403: void ShowIndustryViewWindow(int industry); truelight@4403: void BuildOilRig(TileIndex tile); truelight@4403: void DeleteOilRig(TileIndex tile); truelight@4403: truelight@4403: static byte _industry_sound_ctr; truelight@4403: static TileIndex _industry_sound_tile; truelight@4403: 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: truelight@4346: /* We don't use FOR_ALL here, because FOR_ALL skips invalid items. truelight@4346: * TODO - This is just a temporary stage, this will be removed. */ tron@4976: for (i = GetIndustry(start_item); i != NULL; i = (i->index + 1U < GetIndustryPoolSize()) ? GetIndustry(i->index + 1U) : NULL) i->index = start_item++; truelight@1267: } truelight@1267: matthijs@5216: DEFINE_OLD_POOL(Industry, Industry, IndustryPoolNewBlock, NULL) truelight@1267: belugas@3499: /** belugas@3499: * Retrieve the type for this industry. Although it is accessed by a tile, belugas@3499: * it will return the general type of industry, and not the sprite index belugas@3499: * as would do GetIndustryGfx. belugas@3499: * The same information can be accessed by looking at Industry->type belugas@3499: * @param tile that is queried belugas@3499: * @pre IsTileType(tile, MP_INDUSTRY) belugas@3499: * @return general type for this industry, as defined in industry.h belugas@3499: **/ belugas@3499: IndustryType GetIndustryType(TileIndex tile) belugas@3499: { belugas@3499: IndustryGfx this_type = GetIndustryGfx(tile); belugas@3499: IndustryType iloop; belugas@3499: belugas@3499: assert(IsTileType(tile, MP_INDUSTRY)); belugas@3499: belugas@3499: for (iloop = IT_COAL_MINE; iloop < IT_END; iloop += 1) { belugas@3545: if (IS_BYTE_INSIDE(this_type, industry_gfx_Solver[iloop].MinGfx, belugas@3553: industry_gfx_Solver[iloop].MaxGfx+1)) { belugas@3499: return iloop; belugas@3499: } belugas@3499: } belugas@3499: belugas@3499: return IT_INVALID; //we have not found equivalent, whatever the reason belugas@3499: } truelight@0: belugas@3662: /** belugas@3662: * Accessor for array _industry_specs. belugas@3662: * This will ensure at once : proper access and belugas@3662: * not allowing modifications of it. belugas@3669: * @param thistype of industry (which is the index in _industry_specs) belugas@3662: * @pre thistype < IT_END belugas@3662: **/ belugas@3689: const IndustrySpec *GetIndustrySpec(IndustryType thistype) belugas@3662: { belugas@3662: assert(thistype < IT_END); belugas@3662: return &_industry_specs[thistype]; belugas@3662: } belugas@3662: truelight@4403: void DestroyIndustry(Industry *i) truelight@4403: { truelight@4403: BEGIN_TILE_LOOP(tile_cur, i->width, i->height, i->xy); truelight@4403: if (IsTileType(tile_cur, MP_INDUSTRY)) { truelight@4403: if (GetIndustryIndex(tile_cur) == i->index) { truelight@4403: DoClearSquare(tile_cur); truelight@4403: } truelight@4403: } else if (IsTileType(tile_cur, MP_STATION) && IsOilRig(tile_cur)) { truelight@4403: DeleteOilRig(tile_cur); truelight@4403: } truelight@4403: END_TILE_LOOP(tile_cur, i->width, i->height, i->xy); truelight@4403: truelight@4403: if (i->type == IT_FARM || i->type == IT_FARM_2) { truelight@4403: /* Remove the farmland and convert it to regular tiles over time. */ truelight@4403: BEGIN_TILE_LOOP(tile_cur, 42, 42, i->xy - TileDiffXY(21, 21)) { Darkvater@4815: tile_cur = TILE_MASK(tile_cur); truelight@4403: if (IsTileType(tile_cur, MP_CLEAR) && IsClearGround(tile_cur, CLEAR_FIELDS) && truelight@4403: GetIndustryIndexOfField(tile_cur) == i->index) { truelight@4403: SetIndustryIndexOfField(tile_cur, INVALID_INDUSTRY); truelight@4403: } truelight@4403: } END_TILE_LOOP(tile_cur, 42, 42, i->xy - TileDiff(21, 21)) truelight@4403: } truelight@4403: truelight@4403: _industry_sort_dirty = true; rubidium@5298: _total_industries--; truelight@4403: DeleteSubsidyWithIndustry(i->index); truelight@4403: DeleteWindowById(WC_INDUSTRY_VIEW, i->index); truelight@4403: InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0); truelight@4403: } truelight@4403: belugas@3290: static void IndustryDrawSugarMine(const TileInfo *ti) truelight@0: { truelight@0: const DrawIndustrySpec1Struct *d; truelight@0: uint32 image; truelight@0: tron@3321: if (!IsIndustryCompleted(ti->tile)) return; truelight@201: rubidium@5435: d = &_draw_industry_spec1[GetIndustryAnimationState(ti->tile)]; truelight@0: peter1138@5668: AddChildSpriteScreen(SPR_IT_SUGAR_MINE_SIEVE + d->image_1, PAL_NONE, d->x, 0); truelight@0: tron@2639: image = d->image_2; peter1138@5668: if (image != 0) AddChildSpriteScreen(SPR_IT_SUGAR_MINE_CLOUDS + image - 1, PAL_NONE, 8, 41); truelight@0: tron@2639: image = d->image_3; tron@2639: if (image != 0) { peter1138@5668: AddChildSpriteScreen(SPR_IT_SUGAR_MINE_PILE + image - 1, PAL_NONE, tron@2639: _drawtile_proc1_x[image - 1], _drawtile_proc1_y[image - 1]); tron@2639: } truelight@0: } truelight@0: belugas@3290: static void IndustryDrawToffeeQuarry(const TileInfo *ti) truelight@0: { truelight@0: int x = 0; truelight@201: tron@3321: if (IsIndustryCompleted(ti->tile)) { rubidium@5435: x = _industry_anim_offs[GetIndustryAnimationState(ti->tile)]; truelight@0: if ( (byte)x == 0xFF) truelight@0: x = 0; truelight@0: } truelight@0: peter1138@5668: AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_SHOVEL, PAL_NONE, 22 - x, 24 + x); peter1138@5668: AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_TOFFEE, PAL_NONE, 6, 14); truelight@0: } truelight@0: belugas@3290: static void IndustryDrawBubbleGenerator( const TileInfo *ti) truelight@0: { tron@3321: if (IsIndustryCompleted(ti->tile)) { peter1138@5668: AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_BUBBLE, PAL_NONE, 5, _industry_anim_offs_2[GetIndustryAnimationState(ti->tile)]); tron@2639: } else { peter1138@5668: AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_SPRING, PAL_NONE, 3, 67); truelight@0: } truelight@0: } truelight@0: belugas@3290: static void IndustryDrawToyFactory(const TileInfo *ti) truelight@0: { truelight@0: const DrawIndustrySpec4Struct *d; truelight@0: rubidium@5435: d = &_industry_anim_offs_3[GetIndustryAnimationState(ti->tile)]; truelight@0: truelight@0: if (d->image_1 != 0xFF) { peter1138@5668: AddChildSpriteScreen(SPR_IT_TOY_FACTORY_CLAY, PAL_NONE, 50 - d->image_1 * 2, 96 + d->image_1); truelight@0: } truelight@0: truelight@0: if (d->image_2 != 0xFF) { peter1138@5668: AddChildSpriteScreen(SPR_IT_TOY_FACTORY_ROBOT, PAL_NONE, 16 - d->image_2 * 2, 100 + d->image_2); truelight@0: } truelight@0: peter1138@5668: AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP, PAL_NONE, 7, d->image_3); peter1138@5668: AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP_HOLDER, PAL_NONE, 0, 42); truelight@0: } truelight@0: belugas@3290: static void IndustryDrawCoalPlantSparks(const TileInfo *ti) truelight@0: { tron@3321: if (IsIndustryCompleted(ti->tile)) { rubidium@5435: uint image = GetIndustryAnimationState(ti->tile); tron@3321: truelight@0: if (image != 0 && image < 7) { belugas@3290: AddChildSpriteScreen(image + SPR_IT_POWER_PLANT_TRANSFORMERS, peter1138@5668: PAL_NONE, belugas@3290: _coal_plant_sparks_x[image - 1], belugas@3290: _coal_plant_sparks_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] = { belugas@3290: IndustryDrawSugarMine, belugas@3290: IndustryDrawToffeeQuarry, belugas@3290: IndustryDrawBubbleGenerator, belugas@3290: IndustryDrawToyFactory, belugas@3290: IndustryDrawCoalPlantSparks, truelight@0: }; truelight@0: truelight@0: static void DrawTile_Industry(TileInfo *ti) truelight@0: { rubidium@5436: const IndustryGfx gfx = GetIndustryGfx(ti->tile); belugas@3662: const Industry *ind; belugas@3654: const DrawBuildingsTileStruct *dits; truelight@0: byte z; peter1138@5668: SpriteID image; peter1138@5668: SpriteID pal; truelight@0: truelight@0: /* Pointer to industry */ tron@3314: ind = GetIndustryByTile(ti->tile); truelight@0: truelight@0: /* Retrieve pointer to the draw industry tile struct */ rubidium@5436: dits = &_industry_draw_tile_data[gfx << 2 | (_industry_section_draw_animation_state[gfx] ? rubidium@5436: GetIndustryAnimationState(ti->tile) & 3 : rubidium@5436: GetIndustryConstructionStage(ti->tile))]; truelight@0: peter1138@5668: image = dits->ground.sprite; peter1138@5668: if (HASBIT(image, PALETTE_MODIFIER_COLOR) && dits->ground.pal == PAL_NONE) { peter1138@5668: pal = GENERAL_SPRITE_COLOR(ind->random_color); peter1138@5668: } else { peter1138@5668: pal = dits->ground.pal; peter1138@5668: } truelight@0: truelight@0: z = ti->z; truelight@0: /* Add bricks below the industry? */ tron@3636: if (ti->tileh != SLOPE_FLAT) { peter1138@5668: AddSortableSpriteToDraw(SPR_FOUNDATION_BASE + ti->tileh, PAL_NONE, ti->x, ti->y, 16, 16, 7, z); peter1138@5668: AddChildSpriteScreen(image, pal, 31, 1); tron@3645: z += TILE_HEIGHT; truelight@0: } else { truelight@0: /* Else draw regular ground */ peter1138@5668: DrawGroundSprite(image, pal); truelight@0: } truelight@0: truelight@0: /* Add industry on top of the ground? */ peter1138@5668: image = dits->building.sprite; tron@2639: if (image != 0) { peter1138@5668: if (_display_opt & DO_TRANS_BUILDINGS) { peter1138@5668: SETBIT(image, PALETTE_MODIFIER_TRANSPARENT); peter1138@5668: pal = PALETTE_TO_TRANSPARENT; peter1138@5668: } else { peter1138@5668: pal = dits->building.pal; peter1138@5668: } truelight@201: peter1138@5668: AddSortableSpriteToDraw(image, pal, 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: { belugas@3654: int proc = dits->draw_proc - 1; tron@2639: if (proc >= 0) _industry_draw_tile_procs[proc](ti); truelight@0: } truelight@0: } truelight@0: tron@4231: static uint GetSlopeZ_Industry(TileIndex tile, uint x, uint y) tron@2537: { tron@4231: return GetTileMaxZ(tile); truelight@0: } truelight@0: tron@3636: static Slope GetSlopeTileh_Industry(TileIndex tile, Slope tileh) tron@2548: { tron@3636: return SLOPE_FLAT; dominik@39: } dominik@39: tron@1977: static void GetAcceptedCargo_Industry(TileIndex tile, AcceptedCargo ac) truelight@0: { belugas@3499: IndustryGfx gfx = GetIndustryGfx(tile); tron@2598: CargoID a; truelight@0: celestar@3494: a = _industry_section_accepts_1[gfx]; tron@2598: if (a != CT_INVALID) ac[a] = (a == 0) ? 1 : 8; truelight@0: celestar@3494: a = _industry_section_accepts_2[gfx]; tron@2598: if (a != CT_INVALID) ac[a] = 8; truelight@0: celestar@3494: a = _industry_section_accepts_3[gfx]; 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: { belugas@3662: const Industry *i = GetIndustryByTile(tile); truelight@0: truelight@0: td->owner = i->owner; belugas@4942: td->str = GetIndustrySpec(i->type)->name; tron@3321: if (!IsIndustryCompleted(tile)) { 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: { belugas@3662: Industry *i = GetIndustryByTile(tile); truelight@0: rubidium@4434: /* water can destroy industries rubidium@4434: * in editor you can bulldoze industries rubidium@4434: * with magic_bulldozer cheat you can destroy industries rubidium@4434: * (area around OILRIG is water, so water shouldn't flood it rubidium@4434: */ darkvater@149: if ((_current_player != OWNER_WATER && _game_mode != GM_EDITOR && darkvater@149: !_cheats.magic_bulldozer.value) || tron@4077: (_current_player == OWNER_WATER && i->type == IT_OIL_RIG)) { belugas@4942: SetDParam(0, GetIndustrySpec(i->type)->name); 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: tron@1977: static void TransportIndustryGoods(TileIndex tile) truelight@0: { belugas@3662: Industry *i = GetIndustryByTile(tile); belugas@3669: const IndustrySpec *indspec = GetIndustrySpec(i->type); truelight@0: uint cw, am; truelight@0: tron@2639: cw = min(i->cargo_waiting[0], 255); belugas@3669: if (cw > indspec->minimal_cargo/* && i->produced_cargo[0] != 0xFF*/) { 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@3331: if (am != 0) { celestar@3494: uint newgfx = _industry_produce_section[GetIndustryGfx(tile)]; tron@3331: tron@3331: if (newgfx != 0xFF) { belugas@3495: ResetIndustryConstructionStage(tile); belugas@3495: SetIndustryCompleted(tile, true); tron@3331: SetIndustryGfx(tile, newgfx); tron@3331: MarkTileDirtyByTile(tile); tron@3331: } truelight@0: } truelight@0: } truelight@0: truelight@0: cw = min(i->cargo_waiting[1], 255); belugas@3669: if (cw > indspec->minimal_cargo) { 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: { tron@3331: byte m; truelight@0: tron@3331: switch (GetIndustryGfx(tile)) { belugas@3545: case GFX_SUGAR_MINE_SIEVE: truelight@0: if ((_tick_counter & 1) == 0) { rubidium@5435: m = GetIndustryAnimationState(tile) + 1; truelight@201: tron@2952: switch (m & 7) { rubidium@4434: 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: } rubidium@5435: SetIndustryAnimationState(tile, m); truelight@0: truelight@0: MarkTileDirtyByTile(tile); truelight@0: } truelight@0: break; truelight@0: belugas@3545: case GFX_TOFFEE_QUARY: truelight@0: if ((_tick_counter & 3) == 0) { rubidium@5435: m = GetIndustryAnimationState(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: } rubidium@5435: SetIndustryAnimationState(tile, m); truelight@0: truelight@0: MarkTileDirtyByTile(tile); truelight@0: } truelight@0: break; truelight@0: belugas@3545: case GFX_BUBBLE_CATCHER: rubidium@5435: if ((_tick_counter & 1) == 0) { rubidium@5435: m = GetIndustryAnimationState(tile); truelight@0: truelight@0: if (++m >= 40) { truelight@0: m = 0; truelight@0: DeleteAnimatedTile(tile); truelight@0: } rubidium@5435: SetIndustryAnimationState(tile, m); truelight@0: truelight@0: MarkTileDirtyByTile(tile); truelight@0: } truelight@0: break; truelight@0: truelight@0: // Sparks on a coal plant belugas@3545: case GFX_POWERPLANT_SPARKS: truelight@0: if ((_tick_counter & 3) == 0) { rubidium@5435: m = GetIndustryAnimationState(tile); rubidium@5435: if (m == 6) { rubidium@5435: SetIndustryAnimationState(tile, 0); truelight@0: DeleteAnimatedTile(tile); truelight@0: } else { rubidium@5435: SetIndustryAnimationState(tile, m + 1); truelight@0: MarkTileDirtyByTile(tile); truelight@0: } truelight@0: } truelight@0: break; truelight@0: belugas@3545: case GFX_TOY_FACTORY: truelight@0: if ((_tick_counter & 1) == 0) { rubidium@5435: m = GetIndustryAnimationState(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: belugas@3538: if (m >= 50) { belugas@3538: int n = GetIndustryAnimationLoop(tile) + 1; belugas@3538: m = 0; belugas@3538: if (n >= 8) { belugas@3538: n = 0; belugas@3538: DeleteAnimatedTile(tile); belugas@3538: } belugas@3538: SetIndustryAnimationLoop(tile, n); truelight@0: } rubidium@5435: SetIndustryAnimationState(tile, m); truelight@0: MarkTileDirtyByTile(tile); truelight@0: } truelight@0: break; truelight@0: rubidium@5434: case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2: rubidium@5434: case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4: rubidium@5434: case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6: rubidium@5434: case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8: truelight@0: if ((_tick_counter & 3) == 0) { belugas@3499: IndustryGfx gfx = GetIndustryGfx(tile); truelight@0: tron@3331: gfx = (gfx < 155) ? gfx + 1 : 148; tron@3331: SetIndustryGfx(tile, gfx); truelight@0: MarkTileDirtyByTile(tile); truelight@0: } truelight@0: break; truelight@0: rubidium@4583: case GFX_OILWELL_ANIMATED_1: rubidium@4583: case GFX_OILWELL_ANIMATED_2: rubidium@4583: case GFX_OILWELL_ANIMATED_3: truelight@0: if ((_tick_counter & 7) == 0) { truelight@0: bool b = CHANCE16(1,7); belugas@3499: IndustryGfx gfx = GetIndustryGfx(tile); tron@3331: rubidium@5435: m = GetIndustryAnimationState(tile) + 1; rubidium@4583: if (m == 4 && (m = 0, ++gfx) == GFX_OILWELL_ANIMATED_3 + 1 && (gfx = GFX_OILWELL_ANIMATED_1, b)) { rubidium@4583: SetIndustryGfx(tile, GFX_OILWELL_NOT_ANIMATED); rubidium@5435: SetIndustryConstructionStage(tile, 3); truelight@201: DeleteAnimatedTile(tile); truelight@0: } else { rubidium@5435: SetIndustryAnimationState(tile, m); tron@3331: SetIndustryGfx(tile, gfx); truelight@0: MarkTileDirtyByTile(tile); truelight@0: } truelight@0: } truelight@0: break; truelight@0: rubidium@4583: case GFX_COAL_MINE_TOWER_ANIMATED: rubidium@4583: case GFX_COPPER_MINE_TOWER_ANIMATED: rubidium@4583: case GFX_GOLD_MINE_TOWER_ANIMATED: { 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) { rubidium@5435: m = GetIndustryAnimationState(tile); rubidium@5435: if (!(m & 0x40)) { rubidium@5436: SetIndustryAnimationState(tile, m | 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: } rubidium@5435: m = (GetIndustryAnimationState(tile) + 1) | 0x40; truelight@0: if (m > 0xC2) m = 0xC0; rubidium@5435: SetIndustryAnimationState(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: rubidium@5435: m = (GetIndustryAnimationState(tile) & 0xBF) - 1; truelight@0: if (m < 0x80) m = 0x82; rubidium@5435: SetIndustryAnimationState(tile, m); truelight@0: MarkTileDirtyByTile(tile); truelight@0: } truelight@0: } break; truelight@0: } truelight@0: } truelight@0: belugas@3290: static void CreateIndustryEffectSmoke(TileIndex tile) truelight@0: { tron@3773: uint x = TileX(tile) * TILE_SIZE; tron@3773: uint y = TileY(tile) * TILE_SIZE; tron@3773: uint z = GetTileMaxZ(tile); tron@3094: tron@3773: CreateEffectVehicle(x + 15, y + 14, z + 59, EV_CHIMNEY_SMOKE); truelight@0: } truelight@0: belugas@3495: static void MakeIndustryTileBigger(TileIndex tile) truelight@0: { belugas@3495: byte cnt = GetIndustryConstructionCounter(tile) + 1; belugas@3495: byte stage; truelight@0: belugas@3495: if (cnt != 4) { belugas@3495: SetIndustryConstructionCounter(tile, cnt); truelight@0: return; truelight@0: } truelight@0: belugas@3495: stage = GetIndustryConstructionStage(tile) + 1; belugas@3495: SetIndustryConstructionCounter(tile, 0); belugas@3495: SetIndustryConstructionStage(tile, stage); belugas@3495: if (stage == 3) { belugas@3495: SetIndustryCompleted(tile, true); belugas@3495: } truelight@201: truelight@0: MarkTileDirtyByTile(tile); truelight@0: tron@3321: if (!IsIndustryCompleted(tile)) return; truelight@0: tron@3331: switch (GetIndustryGfx(tile)) { rubidium@4583: case GFX_POWERPLANT_CHIMNEY: belugas@3290: CreateIndustryEffectSmoke(tile); truelight@0: break; truelight@0: peter1138@4607: case GFX_OILRIG_1: peter1138@4607: if (GetIndustryGfx(tile + TileDiffXY(0, 1)) == GFX_OILRIG_1) BuildOilRig(tile); truelight@0: break; truelight@0: belugas@3545: case GFX_TOY_FACTORY: belugas@3545: case GFX_BUBBLE_CATCHER: belugas@3545: case GFX_TOFFEE_QUARY: rubidium@5435: SetIndustryAnimationState(tile, 0); belugas@3538: SetIndustryAnimationLoop(tile, 0); truelight@0: break; truelight@0: rubidium@5434: case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2: rubidium@5434: case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4: rubidium@5434: case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6: rubidium@5434: case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8: truelight@0: AddAnimatedTile(tile); truelight@0: break; truelight@0: } truelight@0: } truelight@0: truelight@0: belugas@3290: static void TileLoopIndustry_BubbleGenerator(TileIndex tile) truelight@0: { truelight@0: int dir; truelight@0: Vehicle *v; truelight@0: static const int8 _tileloop_ind_case_161[12] = { rubidium@4344: 11, 0, -4, -14, rubidium@4344: -4, -10, -4, 1, rubidium@4344: 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( celestar@3421: TileX(tile) * TILE_SIZE + _tileloop_ind_case_161[dir + 0], celestar@3421: TileY(tile) * TILE_SIZE + _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: { belugas@3499: IndustryGfx newgfx; rubidium@5435: IndustryGfx gfx; truelight@0: tron@3321: if (!IsIndustryCompleted(tile)) { belugas@3495: MakeIndustryTileBigger(tile); truelight@0: return; truelight@0: } truelight@0: tron@2639: if (_game_mode == GM_EDITOR) return; truelight@0: truelight@0: TransportIndustryGoods(tile); truelight@0: celestar@3494: newgfx = _industry_section_animation_next[GetIndustryGfx(tile)]; tron@3331: if (newgfx != 255) { belugas@3495: ResetIndustryConstructionStage(tile); tron@3331: SetIndustryGfx(tile, newgfx); truelight@0: MarkTileDirtyByTile(tile); truelight@0: return; truelight@0: } truelight@0: rubidium@5435: gfx = GetIndustryGfx(tile); truelight@0: rubidium@5435: switch (gfx) { rubidium@4583: case GFX_OILRIG_1: // coast line at oilrigs rubidium@4583: case GFX_OILRIG_2: rubidium@4583: case GFX_OILRIG_3: rubidium@4583: case GFX_OILRIG_4: rubidium@4583: case GFX_OILRIG_5: dominik@43: TileLoop_Water(tile); dominik@43: break; dominik@43: rubidium@4583: case GFX_COAL_MINE_TOWER_NOT_ANIMATED: rubidium@4583: case GFX_COPPER_MINE_TOWER_NOT_ANIMATED: rubidium@4583: case GFX_GOLD_MINE_TOWER_NOT_ANIMATED: rubidium@5435: if (!(_tick_counter & 0x400) && CHANCE16(1, 2)) { rubidium@5435: switch (gfx) { rubidium@5435: case GFX_COAL_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COAL_MINE_TOWER_ANIMATED; break; rubidium@5435: case GFX_COPPER_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_ANIMATED; break; rubidium@5435: case GFX_GOLD_MINE_TOWER_NOT_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_ANIMATED; break; rubidium@5435: } rubidium@5435: SetIndustryGfx(tile, gfx); rubidium@5435: SetIndustryAnimationState(tile, 0x80); rubidium@5435: AddAnimatedTile(tile); rubidium@5435: } truelight@0: break; truelight@0: rubidium@4583: case GFX_OILWELL_NOT_ANIMATED: rubidium@5435: if (CHANCE16(1, 6)) { rubidium@5435: SetIndustryGfx(tile, GFX_OILWELL_ANIMATED_1); rubidium@5435: SetIndustryAnimationState(tile, 0); rubidium@5435: AddAnimatedTile(tile); rubidium@5435: } truelight@0: break; truelight@0: rubidium@4583: case GFX_COAL_MINE_TOWER_ANIMATED: rubidium@4583: case GFX_COPPER_MINE_TOWER_ANIMATED: rubidium@4583: case GFX_GOLD_MINE_TOWER_ANIMATED: rubidium@5435: if (!(_tick_counter & 0x400)) { rubidium@5435: switch (gfx) { rubidium@5435: case GFX_COAL_MINE_TOWER_ANIMATED: gfx = GFX_COAL_MINE_TOWER_NOT_ANIMATED; break; rubidium@5435: case GFX_COPPER_MINE_TOWER_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_NOT_ANIMATED; break; rubidium@5435: case GFX_GOLD_MINE_TOWER_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_NOT_ANIMATED; break; rubidium@5435: } rubidium@5435: SetIndustryGfx(tile, gfx); rubidium@5435: SetIndustryCompleted(tile, true); rubidium@5435: SetIndustryConstructionStage(tile, 3); rubidium@5435: DeleteAnimatedTile(tile); rubidium@5435: } rubidium@4583: break; rubidium@4583: rubidium@4583: case GFX_POWERPLANT_SPARKS: 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: rubidium@4583: case GFX_COPPER_MINE_CHIMNEY: celestar@3421: CreateEffectVehicleAbove(TileX(tile) * TILE_SIZE + 6, TileY(tile) * TILE_SIZE + 6, 43, EV_SMOKE); tron@2639: break; truelight@0: truelight@0: rubidium@4583: case GFX_TOY_FACTORY: { belugas@3662: Industry *i = GetIndustryByTile(tile); truelight@0: if (i->was_cargo_delivered) { truelight@0: i->was_cargo_delivered = false; belugas@3538: SetIndustryAnimationLoop(tile, 0); truelight@0: AddAnimatedTile(tile); truelight@0: } truelight@0: } truelight@0: break; truelight@0: rubidium@4583: case GFX_BUBBLE_GENERATOR: belugas@3290: TileLoopIndustry_BubbleGenerator(tile); truelight@201: break; truelight@201: rubidium@4583: case GFX_TOFFEE_QUARY: truelight@0: AddAnimatedTile(tile); truelight@0: break; truelight@0: rubidium@4583: case GFX_SUGAR_MINE_SIEVE: 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@3314: ShowIndustryViewWindow(GetIndustryIndex(tile)); truelight@0: } truelight@0: tron@1977: static uint32 GetTileTrackStatus_Industry(TileIndex tile, TransportType mode) truelight@0: { truelight@0: return 0; truelight@0: } truelight@0: Darkvater@3344: static void GetProducedCargo_Industry(TileIndex tile, CargoID *b) truelight@0: { belugas@3662: const Industry *i = GetIndustryByTile(tile); 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: 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@3447: case MP_CLEAR: return IsClearGround(tile, CLEAR_FIELDS) || IsClearGround(tile, CLEAR_SNOW); tron@2955: case MP_TREES: return false; tron@2955: default: return true; truelight@0: } truelight@0: } truelight@0: tron@1048: static bool IsBadFarmFieldTile2(TileIndex tile) truelight@0: { tron@1214: switch (GetTileType(tile)) { tron@3447: case MP_CLEAR: return IsClearGround(tile, CLEAR_SNOW); tron@2955: case MP_TREES: return false; tron@2955: default: return true; truelight@0: } truelight@0: } truelight@0: tron@3157: static void SetupFarmFieldFence(TileIndex tile, int size, byte type, Axis direction) truelight@0: { truelight@0: do { truelight@0: tile = TILE_MASK(tile); truelight@201: tron@1035: if (IsTileType(tile, MP_CLEAR) || IsTileType(tile, MP_TREES)) { rubidium@5587: byte or_ = type; truelight@201: rubidium@5587: if (or_ == 1 && CHANCE16(1, 7)) or_ = 2; truelight@0: tron@3157: if (direction == AXIS_X) { rubidium@5587: SetFenceSE(tile, or_); tron@3157: } else { rubidium@5587: SetFenceSW(tile, or_); truelight@0: } truelight@0: } truelight@201: tron@3157: tile += (direction == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1)); truelight@0: } while (--size); truelight@0: } truelight@0: rubidium@4330: static void PlantFarmField(TileIndex tile, IndustryID industry) truelight@0: { truelight@0: uint size_x, size_y; truelight@0: uint32 r; tron@2133: uint count; tron@2979: uint counter; tron@2979: uint field_type; tron@2979: int type; truelight@0: truelight@0: if (_opt.landscape == LT_HILLY) { celestar@3422: if (GetTileZ(tile) + TILE_HEIGHT * 2 >= _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(); tron@2979: counter = GB(r, 5, 3); tron@2979: field_type = 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@4328: MakeField(cur_tile, field_type, industry); tron@2979: SetClearCounter(cur_tile, counter); tron@2979: MarkTileDirtyByTile(cur_tile); 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@3157: SetupFarmFieldFence(tile - TileDiffXY(1, 0), size_y, type, AXIS_Y); tron@3157: SetupFarmFieldFence(tile - TileDiffXY(0, 1), size_x, type, AXIS_X); tron@3157: SetupFarmFieldFence(tile + TileDiffXY(size_x - 1, 0), size_y, type, AXIS_Y); tron@3157: SetupFarmFieldFence(tile + TileDiffXY(0, size_y - 1), size_x, type, AXIS_X); truelight@0: } truelight@0: truelight@4328: void PlantRandomFarmField(const Industry *i) truelight@4328: { truelight@4328: int x = i->width / 2 + Random() % 31 - 16; truelight@4328: int y = i->height / 2 + Random() % 31 - 16; truelight@4328: truelight@4328: TileIndex tile = TileAddWrap(i->xy, x, y); truelight@4328: truelight@4328: if (tile != INVALID_TILE) PlantFarmField(tile, i->index); truelight@4328: } truelight@4328: belugas@3662: static void MaybePlantFarmField(const Industry *i) truelight@0: { truelight@4328: if (CHANCE16(1, 8)) PlantRandomFarmField(i); truelight@0: } truelight@0: belugas@5118: /** belugas@5118: * Search callback function for ChopLumberMillTrees belugas@5118: * @param tile to test belugas@5118: * @param data that is passed by the caller. In this case, nothing belugas@5118: * @result of the test belugas@5118: */ belugas@5118: static bool SearchLumberMillTrees(TileIndex tile, uint32 data) belugas@5118: { belugas@5118: if (IsTileType(tile, MP_TREES)) { belugas@5118: PlayerID old_player = _current_player; belugas@5118: /* found a tree */ belugas@5118: belugas@5118: _current_player = OWNER_NONE; belugas@5118: _industry_sound_ctr = 1; belugas@5118: _industry_sound_tile = tile; belugas@5118: SndPlayTileFx(SND_38_CHAINSAW, tile); belugas@5118: belugas@5118: DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); belugas@5118: SetTropicZone(tile, TROPICZONE_INVALID); belugas@5118: belugas@5118: _current_player = old_player; belugas@5118: return true; belugas@5118: } belugas@5118: return false; belugas@5118: } belugas@5118: belugas@5118: /** belugas@5118: * Perform a circular search around the Lumber Mill in order to find trees to cut belugas@5118: * @param i industry belugas@5118: */ truelight@0: static void ChopLumberMillTrees(Industry *i) truelight@0: { tron@1977: TileIndex tile = i->xy; tron@2639: belugas@5118: if (!IsIndustryCompleted(tile)) return; ///< Can't proceed if not completed truelight@0: belugas@5118: if (CircularTileSearch(tile, 40, SearchLumberMillTrees, 0)) ///< 40x40 tiles to search belugas@5118: i->cargo_waiting[0] = min(0xffff, i->cargo_waiting[0] + 45); ///< Found a tree, add according value to waiting cargo 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( rubidium@5587: (SoundFx)(_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) { truelight@4346: ProduceIndustryGoods(i); truelight@0: } truelight@0: } truelight@0: truelight@0: tron@3877: static bool CheckNewIndustry_NULL(TileIndex tile) truelight@0: { truelight@0: return true; truelight@0: } truelight@0: tron@3877: static bool CheckNewIndustry_Forest(TileIndex tile) truelight@0: { truelight@0: if (_opt.landscape == LT_HILLY) { tron@3645: if (GetTileZ(tile) < _opt.snow_line + TILE_HEIGHT * 2U) { 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: tron@3877: static bool CheckNewIndustry_OilRefinery(TileIndex tile) tron@3877: { tron@3877: if (_game_mode == GM_EDITOR) return true; truelight@4300: if (DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _patches.oil_refinery_limit) return true; tron@3877: tron@3877: _error_message = STR_483B_CAN_ONLY_BE_POSITIONED; tron@3877: return false; tron@3877: } tron@3877: dominik@7: extern bool _ignore_restrictions; dominik@7: tron@3877: static bool CheckNewIndustry_OilRig(TileIndex tile) truelight@0: { tron@2639: if (_game_mode == GM_EDITOR && _ignore_restrictions) return true; tron@3877: if (TileHeight(tile) == 0 && truelight@4300: DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _patches.oil_refinery_limit) return true; truelight@0: truelight@0: _error_message = STR_483B_CAN_ONLY_BE_POSITIONED; truelight@0: return false; truelight@0: } truelight@0: tron@3877: static bool CheckNewIndustry_Farm(TileIndex tile) truelight@0: { truelight@0: if (_opt.landscape == LT_HILLY) { celestar@3422: if (GetTileZ(tile) + TILE_HEIGHT * 2 >= _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@3877: static bool CheckNewIndustry_Plantation(TileIndex tile) truelight@0: { belugas@3379: if (GetTropicZone(tile) == TROPICZONE_DESERT) { 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@3877: static bool CheckNewIndustry_Water(TileIndex tile) truelight@0: { belugas@3379: if (GetTropicZone(tile) != TROPICZONE_DESERT) { 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@3877: static bool CheckNewIndustry_Lumbermill(TileIndex tile) truelight@0: { belugas@3379: if (GetTropicZone(tile) != TROPICZONE_RAINFOREST) { 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@3877: static bool CheckNewIndustry_BubbleGen(TileIndex tile) truelight@0: { tron@3645: return GetTileZ(tile) <= TILE_HEIGHT * 4; truelight@0: } truelight@0: tron@3877: typedef bool CheckNewIndustryProc(TileIndex tile); belugas@3663: static CheckNewIndustryProc * const _check_new_industry_procs[CHECK_END] = { truelight@0: CheckNewIndustry_NULL, truelight@0: CheckNewIndustry_Forest, tron@3877: CheckNewIndustry_OilRefinery, truelight@0: CheckNewIndustry_Farm, truelight@0: CheckNewIndustry_Plantation, truelight@0: CheckNewIndustry_Water, truelight@0: CheckNewIndustry_Lumbermill, truelight@0: CheckNewIndustry_BubbleGen, tron@3877: CheckNewIndustry_OilRig 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: belugas@3662: static const Town *CheckMultipleIndustryInTown(TileIndex tile, int type) truelight@0: { belugas@3662: const Town *t; belugas@3662: 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@4346: if (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@4300: static bool CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTileTable *it, int type) 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@3440: if (it->gfx == 0xff) continue; truelight@0: return false; truelight@0: } truelight@201: tron@3440: if (it->gfx == 0xFF) { tron@3296: if (!IsTileType(cur_tile, MP_WATER) || tron@3636: GetTileSlope(cur_tile, NULL) != SLOPE_FLAT) { tron@3296: return false; tron@3296: } truelight@0: } else { tron@2639: if (!EnsureNoVehicle(cur_tile)) return false; truelight@0: truelight@0: if (type == IT_OIL_RIG) { belugas@5056: if (!IsClearWaterTile(cur_tile)) return false; truelight@0: } else { tron@3636: Slope tileh; truelight@0: belugas@5056: if (IsClearWaterTile(cur_tile)) return false; tron@3296: tron@3296: tileh = GetTileSlope(cur_tile, NULL); tron@3636: if (IsSteepSlope(tileh)) return false; tron@3296: truelight@4301: if (_patches.land_generator != LG_TERRAGENESIS || !_generating_world) { truelight@4300: /* It is almost impossible to have a fully flat land in TG, so what we truelight@4300: * do is that we check if we can make the land flat later on. See truelight@4300: * CheckIfCanLevelIndustryPlatform(). */ truelight@4300: if (tileh != SLOPE_FLAT) { truelight@4300: Slope t; truelight@4300: byte bits = _industry_section_bits[it->gfx]; truelight@201: truelight@4300: if (bits & 0x10) return false; truelight@0: truelight@4300: t = ComplementSlope(tileh); truelight@4300: truelight@4300: if (bits & 1 && (t & SLOPE_NW)) return false; truelight@4300: if (bits & 2 && (t & SLOPE_NE)) return false; truelight@4300: if (bits & 4 && (t & SLOPE_SW)) return false; truelight@4300: if (bits & 8 && (t & SLOPE_SE)) return false; truelight@4300: } truelight@0: } truelight@0: belugas@3499: if (type == IT_BANK_TEMP) { truelight@4300: if (!IsTileType(cur_tile, MP_HOUSE)) { truelight@0: _error_message = STR_029D_CAN_ONLY_BE_BUILT_IN_TOWNS; truelight@0: return false; truelight@0: } belugas@3499: } else if (type == IT_BANK_TROPIC_ARCTIC) { tron@3296: if (!IsTileType(cur_tile, 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@3296: if (!IsTileType(cur_tile, MP_HOUSE)) goto do_clear; truelight@0: } else if (type == IT_WATER_TOWER) { tron@3296: if (!IsTileType(cur_tile, 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: tron@3491: if (CmdFailed(DoCommand(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: truelight@4300: static bool CheckIfIndustryIsAllowed(TileIndex tile, int type, const Town *t) truelight@4300: { truelight@4300: if (type == IT_BANK_TEMP && t->population < 1200) { truelight@4300: _error_message = STR_029D_CAN_ONLY_BE_BUILT_IN_TOWNS; truelight@4300: return false; truelight@4300: } truelight@4300: truelight@4300: if (type == IT_TOY_SHOP && DistanceMax(t->xy, tile) > 9) { truelight@4300: _error_message = STR_0239_SITE_UNSUITABLE; truelight@4300: return false; truelight@4300: } truelight@4300: truelight@4300: return true; truelight@4300: } truelight@4300: truelight@4300: static bool CheckCanTerraformSurroundingTiles(TileIndex tile, uint height, int internal) truelight@4300: { truelight@4300: int size_x, size_y; truelight@4300: uint curh; truelight@4300: truelight@4300: size_x = 2; truelight@4300: size_y = 2; truelight@4300: truelight@4300: /* Check if we don't leave the map */ truelight@4300: if (TileX(tile) == 0 || TileY(tile) == 0 || GetTileType(tile) == MP_VOID) return false; truelight@4300: truelight@4300: tile += TileDiffXY(-1, -1); truelight@4300: BEGIN_TILE_LOOP(tile_walk, size_x, size_y, tile) { truelight@4300: curh = TileHeight(tile_walk); truelight@4300: /* Is the tile clear? */ truelight@4300: if ((GetTileType(tile_walk) != MP_CLEAR) && (GetTileType(tile_walk) != MP_TREES)) truelight@4300: return false; truelight@4300: truelight@4300: /* Don't allow too big of a change if this is the sub-tile check */ rubidium@5587: if (internal != 0 && delta(curh, height) > 1) return false; truelight@4300: truelight@4300: /* Different height, so the surrounding tiles of this tile truelight@4300: * has to be correct too (in level, or almost in level) truelight@4300: * else you get a chain-reaction of terraforming. */ truelight@4300: if (internal == 0 && curh != height) { truelight@4300: if (!CheckCanTerraformSurroundingTiles(tile_walk + TileDiffXY(-1, -1), height, internal + 1)) truelight@4300: return false; truelight@4300: } truelight@4300: } END_TILE_LOOP(tile_walk, size_x, size_y, tile); truelight@4300: truelight@4300: return true; truelight@4300: } truelight@4300: truelight@4300: /** truelight@4300: * This function tries to flatten out the land below an industry, without truelight@4300: * damaging the surroundings too much. truelight@4300: */ truelight@4300: static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, uint32 flags, const IndustryTileTable* it, int type) truelight@4300: { truelight@4300: const int MKEND = -0x80; // used for last element in an IndustryTileTable (see build_industry.h) truelight@4300: int max_x = 0; truelight@4300: int max_y = 0; truelight@4300: TileIndex cur_tile; truelight@4300: uint size_x, size_y; truelight@4300: uint h, curh; truelight@4300: truelight@4300: /* Finds dimensions of largest variant of this industry */ truelight@4300: do { truelight@4300: if (it->ti.x > max_x) max_x = it->ti.x; truelight@4300: if (it->ti.y > max_y) max_y = it->ti.y; truelight@4300: } while ((++it)->ti.x != MKEND); truelight@4300: truelight@4300: /* Remember level height */ truelight@4300: h = TileHeight(tile); truelight@4300: truelight@4300: /* Check that all tiles in area and surrounding are clear truelight@4300: * this determines that there are no obstructing items */ truelight@4300: cur_tile = tile + TileDiffXY(-1, -1); truelight@4300: size_x = max_x + 4; truelight@4300: size_y = max_y + 4; truelight@4300: truelight@4300: /* Check if we don't leave the map */ rubidium@4313: if (TileX(cur_tile) == 0 || TileY(cur_tile) == 0 || TileX(cur_tile) + size_x >= MapMaxX() || TileY(cur_tile) + size_y >= MapMaxY()) return false; truelight@4300: truelight@4300: BEGIN_TILE_LOOP(tile_walk, size_x, size_y, cur_tile) { truelight@4300: curh = TileHeight(tile_walk); truelight@4300: if (curh != h) { truelight@4300: /* This tile needs terraforming. Check if we can do that without truelight@4300: * damaging the surroundings too much. */ truelight@4300: if (!CheckCanTerraformSurroundingTiles(tile_walk, h, 0)) return false; truelight@4300: /* This is not 100% correct check, but the best we can do without modifying the map. truelight@4300: * What is missing, is if the difference in height is more than 1.. */ truelight@4300: if (CmdFailed(DoCommand(tile_walk, 8, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND))) return false; truelight@4300: } truelight@4300: } END_TILE_LOOP(tile_walk, size_x, size_y, cur_tile) truelight@4300: truelight@4300: if (flags & DC_EXEC) { truelight@4300: /* Terraform the land under the industry */ truelight@4300: BEGIN_TILE_LOOP(tile_walk, size_x, size_y, cur_tile) { truelight@4300: curh = TileHeight(tile_walk); truelight@4300: while (curh != h) { truelight@4300: /* We give the terraforming for free here, because we can't calculate truelight@4300: * exact cost in the test-round, and as we all know, that will cause truelight@4300: * a nice assert if they don't match ;) */ truelight@4300: DoCommand(tile_walk, 8, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND); truelight@4300: curh += (curh > h) ? -1 : 1; truelight@4300: } truelight@4300: } END_TILE_LOOP(tile_walk, size_x, size_y, cur_tile) truelight@4300: } truelight@4300: truelight@4300: return true; truelight@4300: } truelight@4300: truelight@4300: tron@1977: static bool CheckIfTooCloseToIndustry(TileIndex tile, int type) truelight@0: { belugas@3669: const IndustrySpec *indspec = GetIndustrySpec(type); belugas@3662: const Industry *i; truelight@0: truelight@0: // accepting industries won't be close, not even with patch belugas@3669: if (_patches.same_industry_close && indspec->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@4346: if (DistanceMax(tile, i->xy) <= 14 && belugas@3669: indspec->accepts_cargo[0] != CT_INVALID && belugas@3669: indspec->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@4346: if ((i->type == indspec->conflicting[0] || i->type == indspec->conflicting[1] || i->type == indspec->conflicting[2]) && 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@4346: /* We don't use FOR_ALL here, because FOR_ALL skips invalid items. truelight@4346: * TODO - This is just a temporary stage, this will be removed. */ tron@4976: for (i = GetIndustry(0); i != NULL; i = (i->index + 1U < GetIndustryPoolSize()) ? GetIndustry(i->index + 1U) : NULL) { truelight@4346: IndustryID index = i->index; truelight@1267: truelight@4346: if (IsValidIndustry(i)) continue; truelight@919: truelight@4346: memset(i, 0, sizeof(*i)); truelight@4346: i->index = index; truelight@4346: truelight@4346: return i; truelight@0: } truelight@1267: truelight@1267: /* Check if we can add a block to the pool */ tron@4976: return AddBlockToPool(&_Industry_pool) ? AllocateIndustry() : NULL; truelight@0: } truelight@0: rubidium@5587: static void DoCreateNewIndustry(Industry *i, TileIndex tile, int type, const IndustryTileTable *it, const Town *t, Owner owner) truelight@0: { belugas@3669: const IndustrySpec *indspec = GetIndustrySpec(type); truelight@0: uint32 r; truelight@0: int j; truelight@0: rubidium@5319: _total_industries++; truelight@0: i->xy = tile; truelight@0: i->width = i->height = 0; truelight@0: i->type = type; truelight@0: belugas@3669: i->produced_cargo[0] = indspec->produced_cargo[0]; belugas@3669: i->produced_cargo[1] = indspec->produced_cargo[1]; belugas@3669: i->accepts_cargo[0] = indspec->accepts_cargo[0]; belugas@3669: i->accepts_cargo[1] = indspec->accepts_cargo[1]; belugas@3669: i->accepts_cargo[2] = indspec->accepts_cargo[2]; belugas@3669: i->production_rate[0] = indspec->production_rate[0]; belugas@3669: i->production_rate[1] = indspec->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(); belugas@4942: i->random_color = 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; rubidium@4329: 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: tron@3440: if (it->gfx != 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: tron@3491: DoCommand(cur_tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); truelight@0: tron@3440: MakeIndustry(cur_tile, i->index, it->gfx); rubidium@5435: if (_generating_world) { rubidium@5435: SetIndustryConstructionCounter(cur_tile, 3); rubidium@5435: SetIndustryConstructionStage(cur_tile, 2); rubidium@5435: } 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@4328: for (j = 0; j != 50; j++) PlantRandomFarmField(i); truelight@0: } truelight@0: _industry_sort_dirty = true; truelight@0: InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0); truelight@0: } truelight@0: truelight@4300: static Industry *CreateNewIndustryHelper(TileIndex tile, IndustryType type, uint32 flags, const IndustrySpec *indspec, const IndustryTileTable *it) truelight@4300: { truelight@4300: const Town *t; truelight@4300: Industry *i; truelight@4300: truelight@4300: if (!CheckIfIndustryTilesAreFree(tile, it, type)) return NULL; truelight@4300: if (_patches.land_generator == LG_TERRAGENESIS && _generating_world && !CheckIfCanLevelIndustryPlatform(tile, 0, it, type)) return NULL; truelight@4300: if (!_check_new_industry_procs[indspec->check_proc](tile)) return NULL; truelight@4300: if (!CheckIfTooCloseToIndustry(tile, type)) return NULL; truelight@4300: truelight@4300: t = CheckMultipleIndustryInTown(tile, type); truelight@4300: if (t == NULL) return NULL; truelight@4300: truelight@4300: if (!CheckIfIndustryIsAllowed(tile, type, t)) return NULL; truelight@4300: if (!CheckSuitableIndustryPos(tile)) return NULL; truelight@4300: truelight@4300: i = AllocateIndustry(); truelight@4300: if (i == NULL) return NULL; truelight@4300: truelight@4300: if (flags & DC_EXEC) { truelight@4300: CheckIfCanLevelIndustryPlatform(tile, DC_EXEC, it, type); truelight@4300: DoCreateNewIndustry(i, tile, type, it, t, OWNER_NONE); truelight@4300: } truelight@4300: truelight@4300: return i; truelight@4300: } truelight@4300: Darkvater@1786: /** Build/Fund an industry tron@3491: * @param tile tile 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: */ tron@3491: int32 CmdBuildIndustry(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) truelight@0: { truelight@0: int num; truelight@0: const IndustryTileTable * const *itt; truelight@0: const IndustryTileTable *it; belugas@3669: const IndustrySpec *indspec; truelight@0: truelight@0: SET_EXPENSES_TYPE(EXPENSES_OTHER); truelight@0: belugas@4965: indspec = GetIndustrySpec(p1); tron@2639: belugas@4965: /* Check if the to-be built/founded industry is available for this climate. */ belugas@4965: if (!HASBIT(indspec->climate_availability, _opt_ptr->landscape)) return CMD_ERROR; truelight@0: 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 && belugas@3669: indspec->accepts_cargo[0] == CT_INVALID && belugas@3669: indspec->accepts_cargo[1] == CT_INVALID && belugas@3669: indspec->accepts_cargo[2] == CT_INVALID && tron@2638: p1 != IT_LUMBER_MILL) { tron@2638: return CMD_ERROR; tron@2638: } truelight@0: belugas@3669: num = indspec->num_table; belugas@3669: itt = indspec->table; truelight@0: truelight@0: do { Darkvater@1786: if (--num < 0) return_cmd_error(STR_0239_SITE_UNSUITABLE); truelight@4300: } while (!CheckIfIndustryTilesAreFree(tile, it = itt[num], p1)); truelight@0: truelight@4300: if (CreateNewIndustryHelper(tile, p1, flags, indspec, it) == NULL) return CMD_ERROR; truelight@201: belugas@3689: return (_price.build_industry >> 5) * indspec->cost_multiplier; truelight@0: } truelight@0: truelight@0: belugas@3538: Industry *CreateNewIndustry(TileIndex tile, IndustryType type) truelight@0: { truelight@4300: const IndustrySpec *indspec = GetIndustrySpec(type); truelight@4300: const IndustryTileTable *it = indspec->table[RandomRange(indspec->num_table)]; truelight@0: truelight@4300: return CreateNewIndustryHelper(tile, type, DC_EXEC, indspec, it); truelight@0: } truelight@0: truelight@110: static const byte _numof_industry_table[4][12] = { belugas@3669: // difficulty settings for number of industries belugas@3669: {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, //none belugas@3669: {0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5}, //low belugas@3669: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, //normal belugas@3669: {0, 2, 3, 4, 6, 7, 8, 9, 10, 10, 10}, //high truelight@0: }; truelight@0: belugas@3669: static void PlaceInitialIndustry(IndustryType 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: truelight@4300: IncreaseGeneratingWorldProgress(GWP_INDUSTRY); truelight@4300: 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@4300: uint i = 0; truelight@4300: truelight@4300: /* Find the total amount of industries */ truelight@4300: b = _industry_create_table[_opt.landscape]; truelight@4300: do { truelight@4300: int num = _numof_industry_table[_opt.diff.number_industries][b[0]]; truelight@4300: truelight@4300: if (b[1] == IT_OIL_REFINERY || b[1] == IT_OIL_RIG) { truelight@4300: /* These are always placed next to the coastline, so we scale by the perimeter instead. */ truelight@4300: num = ScaleByMapSize1D(num); truelight@4300: } else { truelight@4300: num = ScaleByMapSize(num); truelight@4300: } truelight@4300: truelight@4300: i += num; truelight@4300: } while ( (b+=2)[0] != 0); truelight@4300: SetGeneratingWorldProgress(GWP_INDUSTRY, i); 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: belugas@3496: /* Change industry production or do closure */ truelight@0: static void ExtChangeIndustryProduction(Industry *i) truelight@0: { truelight@1320: bool closeit = true; truelight@0: int j; belugas@3669: const IndustrySpec *indspec = GetIndustrySpec(i->type); truelight@0: belugas@4924: switch (indspec->life_type) { belugas@3496: case INDUSTRYLIFE_NOT_CLOSABLE: truelight@1320: return; truelight@201: belugas@3496: case INDUSTRYLIFE_CLOSABLE: rubidium@4329: 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(); rubidium@5587: int old_prod, new_prod, percent; truelight@1320: int mag; truelight@1320: rubidium@5587: new_prod = old_prod = i->production_rate[j]; pasky@1603: if (CHANCE16I(20, 1024, r)) rubidium@5587: new_prod -= ((RandomRange(50) + 10) * old_prod) >> 8; pasky@1603: if (CHANCE16I(20 + (i->pct_transported[j] * 20 >> 8), 1024, r >> 16)) rubidium@5587: new_prod += ((RandomRange(50) + 10) * old_prod) >> 8; truelight@1320: rubidium@5587: new_prod = clamp(new_prod, 0, 255); rubidium@5587: if (new_prod == old_prod) { truelight@1320: closeit = false; truelight@1320: continue; truelight@1320: } truelight@1320: rubidium@5587: percent = new_prod * 100 / old_prod - 100; rubidium@5587: i->production_rate[j] = new_prod; truelight@1320: rubidium@5587: if (new_prod >= indspec->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: belugas@3496: /* If industry will be closed down, show this */ truelight@0: if (closeit) { truelight@0: i->prod_level = 0; ludde@2070: SetDParam(0, i->index); tron@2639: AddNewsItem( belugas@3669: indspec->closure_text, 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) { rubidium@4329: 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) { rubidium@4329: 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] = { rubidium@4344: {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}, rubidium@4344: {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}, rubidium@4344: {21, 21, 21, 24, 22, 22, 22, 22, 23, 23, 16, 16, 16, 4, 4, 19, 19, 19, 13, 13, 20, 20, 20, 11, 11, 11, 17, 17, 17, 10, 10, 10}, rubidium@4344: {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: rubidium@4297: if (type == IT_OIL_WELL && _cur_year > 1950) return; rubidium@4297: if (type == IT_OIL_RIG && _cur_year < 1960) 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: belugas@4942: SetDParam(0, GetIndustrySpec(type)->name); tron@534: SetDParam(1, i->town->index); tron@2260: AddNewsItem( celestar@3581: (type != IT_FOREST && type != IT_FRUIT_PLANTATION && type != IT_RUBBER_PLANTATION && type != IT_COTTON_CANDY) ? 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; belugas@3669: const IndustrySpec *indspec = GetIndustrySpec(type); truelight@201: belugas@4924: switch (indspec->life_type) { belugas@3496: case INDUSTRYLIFE_NOT_CLOSABLE: truelight@1320: return; truelight@0: belugas@3496: case INDUSTRYLIFE_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: belugas@3669: str = indspec->production_up_text; truelight@1320: } truelight@1320: } else { truelight@1320: /* Decrease production */ truelight@1320: if (i->prod_level == 4) { truelight@1320: i->prod_level = 0; belugas@3669: str = indspec->closure_text; 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: belugas@3669: str = indspec->production_down_text; truelight@1320: } truelight@0: } truelight@0: } truelight@1320: break; truelight@1320: belugas@3496: case INDUSTRYLIFE_CLOSABLE: truelight@1320: /* maybe close */ rubidium@4329: if ( (byte)(_cur_year - i->last_prod_year) >= 5 && CHANCE16(1,2)) { truelight@1320: i->prod_level = 0; belugas@3669: str = indspec->closure_text; 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) { truelight@4346: 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()); matthijs@5247: } else if (!_patches.smooth_economy) { truelight@4356: i = GetRandomIndustry(); truelight@4356: if (i != NULL) 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: { tron@4976: CleanPool(&_Industry_pool); tron@4976: AddBlockToPool(&_Industry_pool); truelight@919: truelight@0: _total_industries = 0; truelight@0: _industry_sort_dirty = true; rubidium@4587: _industry_sound_tile = 0; truelight@0: } truelight@0: rubidium@5587: extern const TileTypeProcs _tile_type_industry_procs = { rubidium@4344: DrawTile_Industry, /* draw_tile_proc */ rubidium@4344: GetSlopeZ_Industry, /* get_slope_z_proc */ rubidium@4344: ClearTile_Industry, /* clear_tile_proc */ rubidium@4434: GetAcceptedCargo_Industry, /* get_accepted_cargo_proc */ rubidium@4344: GetTileDesc_Industry, /* get_tile_desc_proc */ rubidium@4344: GetTileTrackStatus_Industry, /* get_tile_track_status_proc */ rubidium@4344: ClickTile_Industry, /* click_tile_proc */ rubidium@4344: AnimateTile_Industry, /* animate_tile_proc */ rubidium@4344: TileLoop_Industry, /* tile_loop_proc */ rubidium@4344: ChangeTileOwner_Industry, /* change_tile_owner_proc */ rubidium@4344: GetProducedCargo_Industry, /* get_produced_cargo_proc */ rubidium@4344: NULL, /* vehicle_enter_tile_proc */ rubidium@4344: GetSlopeTileh_Industry, /* get_slope_tileh_proc */ truelight@0: }; truelight@0: Darkvater@1881: static const SaveLoad _industry_desc[] = { rubidium@4344: SLE_CONDVAR(Industry, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), rubidium@4344: SLE_CONDVAR(Industry, xy, SLE_UINT32, 6, SL_MAX_VERSION), rubidium@4344: SLE_VAR(Industry, width, SLE_UINT8), rubidium@4344: SLE_VAR(Industry, height, SLE_UINT8), rubidium@4344: SLE_REF(Industry, town, REF_TOWN), rubidium@4344: SLE_ARR(Industry, produced_cargo, SLE_UINT8, 2), rubidium@4344: SLE_ARR(Industry, cargo_waiting, SLE_UINT16, 2), rubidium@4344: SLE_ARR(Industry, production_rate, SLE_UINT8, 2), rubidium@4344: SLE_ARR(Industry, accepts_cargo, SLE_UINT8, 3), rubidium@4344: SLE_VAR(Industry, prod_level, SLE_UINT8), rubidium@4344: SLE_ARR(Industry, last_mo_production, SLE_UINT16, 2), rubidium@4344: SLE_ARR(Industry, last_mo_transported, SLE_UINT16, 2), rubidium@4344: SLE_ARR(Industry, pct_transported, SLE_UINT8, 2), rubidium@4344: SLE_ARR(Industry, total_production, SLE_UINT16, 2), rubidium@4344: SLE_ARR(Industry, total_transported, SLE_UINT16, 2), truelight@0: rubidium@4344: SLE_VAR(Industry, counter, SLE_UINT16), truelight@0: rubidium@4344: SLE_VAR(Industry, type, SLE_UINT8), rubidium@4344: SLE_VAR(Industry, owner, SLE_UINT8), belugas@4942: SLE_VAR(Industry, random_color, SLE_UINT8), rubidium@4344: SLE_CONDVAR(Industry, last_prod_year, SLE_FILE_U8 | SLE_VAR_I32, 0, 30), rubidium@4344: SLE_CONDVAR(Industry, last_prod_year, SLE_INT32, 31, SL_MAX_VERSION), rubidium@4344: SLE_VAR(Industry, was_cargo_delivered, SLE_UINT8), truelight@0: truelight@0: // reserve extra space in savegame here. (currently 32 bytes) Darkvater@3222: SLE_CONDNULL(32, 2, SL_MAX_VERSION), 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@4346: SlSetArrayIndex(ind->index); truelight@4346: SlObject(ind, _industry_desc); 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: tron@4976: 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: rubidium@5298: _total_industries++; truelight@0: } truelight@0: } truelight@0: rubidium@5587: extern const ChunkHandler _industry_chunk_handlers[] = { truelight@0: { 'INDY', Save_INDY, Load_INDY, CH_ARRAY | CH_LAST}, truelight@0: };