tron@2186: /* $Id$ */ tron@2186: belugas@6422: /** @file tree_cmd.cpp */ belugas@6422: truelight@0: #include "stdafx.h" Darkvater@1891: #include "openttd.h" celestar@5385: #include "bridge_map.h" tron@3144: #include "clear_map.h" tron@507: #include "table/strings.h" celestar@2148: #include "table/sprites.h" Darkvater@1784: #include "table/tree_land.h" tron@2163: #include "functions.h" tron@679: #include "map.h" maedhros@6343: #include "landscape.h" tron@1209: #include "tile.h" tron@3144: #include "tree_map.h" truelight@0: #include "viewport.h" truelight@0: #include "command.h" truelight@0: #include "town.h" tron@337: #include "sound.h" tron@2153: #include "variables.h" truelight@4300: #include "genworld.h" truelight@4300: truelight@4300: enum TreePlacer { truelight@4300: TP_NONE, truelight@4300: TP_ORIGINAL, truelight@4300: TP_IMPROVED, truelight@4300: }; truelight@0: tron@2981: static TreeType GetRandomTreeType(TileIndex tile, uint seed) truelight@0: { tron@1286: switch (_opt.landscape) { belugas@6357: case LT_TEMPERATE: rubidium@5587: return (TreeType)(seed * TREE_COUNT_TEMPERATE / 256 + TREE_TEMPERATE); truelight@0: belugas@6357: case LT_ARCTIC: rubidium@5587: return (TreeType)(seed * TREE_COUNT_SUB_ARCTIC / 256 + TREE_SUB_ARCTIC); tron@1286: belugas@6357: case LT_TROPIC: belugas@3379: switch (GetTropicZone(tile)) { rubidium@5587: case TROPICZONE_INVALID: return (TreeType)(seed * TREE_COUNT_SUB_TROPICAL / 256 + TREE_SUB_TROPICAL); rubidium@5587: case TROPICZONE_DESERT: return (TreeType)((seed > 12) ? TREE_INVALID : TREE_CACTUS); rubidium@5587: default: return (TreeType)(seed * TREE_COUNT_RAINFOREST / 256 + TREE_RAINFOREST); tron@1286: } tron@1286: tron@1286: default: rubidium@5587: return (TreeType)(seed * TREE_COUNT_TOYLAND / 256 + TREE_TOYLAND); truelight@0: } truelight@0: } truelight@0: tron@2958: static void PlaceTree(TileIndex tile, uint32 r) truelight@0: { tron@2981: TreeType tree = GetRandomTreeType(tile, GB(r, 24, 8)); tron@2088: tron@3441: if (tree != TREE_INVALID) { tron@3441: MakeTree(tile, tree, GB(r, 22, 2), min(GB(r, 16, 3), 6), TREE_GROUND_GRASS, 0); truelight@0: belugas@6422: /* above snowline? */ belugas@6357: if (_opt.landscape == LT_ARCTIC && GetTileZ(tile) > GetSnowLine()) { tron@3441: SetTreeGroundDensity(tile, TREE_GROUND_SNOW_DESERT, 3); rubidium@5587: SetTreeCounter(tile, (TreeGround)GB(r, 24, 3)); tron@2088: } else { rubidium@5587: SetTreeGroundDensity(tile, (TreeGround)GB(r, 28, 1), 0); rubidium@5587: SetTreeCounter(tile, (TreeGround)GB(r, 24, 4)); truelight@0: } truelight@0: } truelight@0: } truelight@0: tron@1977: static void DoPlaceMoreTrees(TileIndex tile) truelight@0: { tron@2088: uint i; truelight@0: tron@2088: for (i = 0; i < 1000; i++) { truelight@0: uint32 r = Random(); tron@2088: int x = GB(r, 0, 5) - 16; tron@2088: int y = GB(r, 8, 5) - 16; tron@2088: uint dist = myabs(x) + myabs(y); tron@2088: TileIndex cur_tile = TILE_MASK(tile + TileDiffXY(x, y)); truelight@0: tron@2955: if (dist <= 13 && tron@2955: IsTileType(cur_tile, MP_CLEAR) && celestar@5385: !IsBridgeAbove(cur_tile) && tron@3447: !IsClearGround(cur_tile, CLEAR_FIELDS) && tron@3447: !IsClearGround(cur_tile, CLEAR_ROCKS)) { tron@2958: PlaceTree(cur_tile, r); truelight@0: } tron@2088: } truelight@0: } truelight@0: rubidium@6247: static void PlaceMoreTrees() truelight@0: { tron@2243: uint i = ScaleByMapSize(GB(Random(), 0, 5) + 25); truelight@0: do { ludde@2051: DoPlaceMoreTrees(RandomTile()); truelight@0: } while (--i); truelight@0: } truelight@0: truelight@4300: /** truelight@4300: * Place a tree at the same height as an existing tree. truelight@4300: * This gives cool effects to the map. truelight@4300: */ truelight@4300: void PlaceTreeAtSameHeight(TileIndex tile, uint height) truelight@4300: { truelight@4300: uint i; truelight@4300: truelight@4300: for (i = 0; i < 1000; i++) { truelight@4300: uint32 r = Random(); truelight@4300: int x = GB(r, 0, 5) - 16; truelight@4300: int y = GB(r, 8, 5) - 16; truelight@4300: TileIndex cur_tile = TILE_MASK(tile + TileDiffXY(x, y)); truelight@4300: truelight@4300: /* Keep in range of the existing tree */ truelight@4300: if (myabs(x) + myabs(y) > 16) continue; truelight@4300: truelight@4300: /* Clear tile, no farm-tiles or rocks */ truelight@4300: if (!IsTileType(cur_tile, MP_CLEAR) || truelight@4300: IsClearGround(cur_tile, CLEAR_FIELDS) || truelight@4300: IsClearGround(cur_tile, CLEAR_ROCKS)) truelight@4300: continue; truelight@4300: truelight@4300: /* Not too much height difference */ rubidium@5587: if (delta(GetTileZ(cur_tile), height) > 2) continue; truelight@4300: truelight@4300: /* Place one tree and quit */ truelight@4300: PlaceTree(cur_tile, r); truelight@4300: break; truelight@4300: } truelight@4300: } truelight@4300: rubidium@6247: void PlaceTreesRandomly() truelight@0: { truelight@4300: uint i, j, ht; truelight@0: tron@1202: i = ScaleByMapSize(1000); truelight@0: do { tron@2088: uint32 r = Random(); tron@2088: TileIndex tile = RandomTileSeed(r); truelight@4300: truelight@4300: IncreaseGeneratingWorldProgress(GWP_TREE); truelight@4300: tron@2955: if (IsTileType(tile, MP_CLEAR) && celestar@5385: !IsBridgeAbove(tile) && tron@3447: !IsClearGround(tile, CLEAR_FIELDS) && tron@3447: !IsClearGround(tile, CLEAR_ROCKS)) { tron@2958: PlaceTree(tile, r); truelight@4300: if (_patches.tree_placer != TP_IMPROVED) continue; truelight@4300: truelight@4300: /* Place a number of trees based on the tile height. truelight@4300: * This gives a cool effect of multiple trees close together. truelight@4300: * It is almost real life ;) */ truelight@4300: ht = GetTileZ(tile); truelight@4300: /* The higher we get, the more trees we plant */ truelight@4300: j = GetTileZ(tile) / TILE_HEIGHT * 2; truelight@4300: while (j--) { truelight@4300: /* Above snowline more trees! */ belugas@6357: if (_opt.landscape == LT_ARCTIC && ht > GetSnowLine()) { truelight@4300: PlaceTreeAtSameHeight(tile, ht); truelight@4300: PlaceTreeAtSameHeight(tile, ht); truelight@4300: }; truelight@4300: truelight@4300: PlaceTreeAtSameHeight(tile, ht); truelight@4300: } truelight@0: } truelight@0: } while (--i); truelight@0: truelight@0: /* place extra trees at rainforest area */ belugas@6357: if (_opt.landscape == LT_TROPIC) { tron@1202: i = ScaleByMapSize(15000); truelight@0: truelight@0: do { tron@2088: uint32 r = Random(); tron@2088: TileIndex tile = RandomTileSeed(r); truelight@4300: truelight@4300: IncreaseGeneratingWorldProgress(GWP_TREE); truelight@4300: celestar@5385: if (IsTileType(tile, MP_CLEAR) && celestar@5385: !IsBridgeAbove(tile) && celestar@5385: !IsClearGround(tile, CLEAR_FIELDS) && celestar@5385: GetTropicZone(tile) == TROPICZONE_RAINFOREST) { tron@2958: PlaceTree(tile, r); truelight@0: } truelight@0: } while (--i); truelight@0: } truelight@0: } truelight@0: rubidium@6247: void GenerateTrees() truelight@0: { truelight@4300: uint i, total; truelight@4300: truelight@4300: if (_patches.tree_placer == TP_NONE) return; truelight@0: belugas@6357: if (_opt.landscape != LT_TOYLAND) PlaceMoreTrees(); tron@2088: truelight@4300: switch (_patches.tree_placer) { belugas@6357: case TP_ORIGINAL: i = _opt.landscape == LT_ARCTIC ? 15 : 6; break; belugas@6357: case TP_IMPROVED: i = _opt.landscape == LT_ARCTIC ? 4 : 2; break; truelight@4300: default: NOT_REACHED(); return; truelight@4300: } truelight@4300: truelight@4300: total = ScaleByMapSize(1000); belugas@6357: if (_opt.landscape == LT_TROPIC) total += ScaleByMapSize(15000); truelight@4300: total *= i; truelight@4300: SetGeneratingWorldProgress(GWP_TREE, total); truelight@4300: truelight@4300: for (; i != 0; i--) { tron@2088: PlaceTreesRandomly(); truelight@0: } truelight@0: } truelight@0: Darkvater@1784: /** Plant a tree. tron@3491: * @param tile start tile of area-drag of tree plantation belugas@6422: * @param flags type of operation Darkvater@1784: * @param p1 tree type, -1 means random. Darkvater@1784: * @param p2 end tile of area-drag truelight@0: */ rubidium@6943: CommandCost CmdPlantTree(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) truelight@0: { tron@3183: StringID msg = INVALID_STRING_ID; rubidium@6943: CommandCost cost; tron@3491: int ex; tron@3491: int ey; Darkvater@2118: int sx, sy, x, y; tron@1286: Darkvater@2892: if (p2 >= MapSize()) return CMD_ERROR; Darkvater@1784: /* Check the tree type. It can be random or some valid value within the current climate */ Darkvater@1784: if (p1 != (uint)-1 && p1 - _tree_base_by_landscape[_opt.landscape] >= _tree_count_by_landscape[_opt.landscape]) return CMD_ERROR; truelight@193: truelight@0: SET_EXPENSES_TYPE(EXPENSES_OTHER); truelight@0: truelight@0: // make sure sx,sy are smaller than ex,ey tron@3491: ex = TileX(tile); tron@3491: ey = TileY(tile); Darkvater@2118: sx = TileX(p2); Darkvater@2118: sy = TileY(p2); tron@6106: if (ex < sx) Swap(ex, sx); tron@6106: if (ey < sy) Swap(ey, sy); truelight@193: Darkvater@2118: for (x = sx; x <= ex; x++) { Darkvater@2118: for (y = sy; y <= ey; y++) { tron@2088: TileIndex tile = TileXY(x, y); tron@1286: tron@2088: switch (GetTileType(tile)) { tron@1286: case MP_TREES: belugas@6422: /* no more space for trees? */ tron@3003: if (_game_mode != GM_EDITOR && GetTreeCount(tile) == 3) { tron@3183: msg = STR_2803_TREE_ALREADY_HERE; tron@1286: continue; truelight@0: } truelight@0: tron@1286: if (flags & DC_EXEC) { tron@2981: AddTreeCount(tile, 1); tron@2088: MarkTileDirtyByTile(tile); tron@1286: } belugas@6422: /* 2x as expensive to add more trees to an existing tile */ rubidium@6950: cost.AddCost(_price.build_trees * 2); tron@1286: break; tron@1286: rubidium@7509: case MP_WATER: rubidium@7509: msg = STR_3807_CAN_T_BUILD_ON_WATER; rubidium@7509: continue; rubidium@7509: break; rubidium@7509: tron@1286: case MP_CLEAR: celestar@5385: if (!IsTileOwner(tile, OWNER_NONE) || celestar@5385: IsBridgeAbove(tile)) { tron@3183: msg = STR_2804_SITE_UNSUITABLE; tron@1286: continue; truelight@0: } truelight@193: tron@2955: switch (GetClearGround(tile)) { rubidium@6950: case CLEAR_FIELDS: cost.AddCost(_price.clear_3); break; rubidium@6950: case CLEAR_ROCKS: cost.AddCost(_price.clear_2); break; tron@2955: default: break; tron@2955: } truelight@0: tron@1286: if (flags & DC_EXEC) { tron@2981: TreeType treetype; tron@3079: uint growth; tron@1286: Darkvater@4850: if (_game_mode != GM_EDITOR && IsValidPlayer(_current_player)) { tron@2088: Town *t = ClosestTownFromTile(tile, _patches.dist_local_authority); tron@1286: if (t != NULL) tron@1286: ChangeTownRating(t, RATING_TREE_UP_STEP, RATING_TREE_MAXIMUM); tron@1286: } tron@1286: rubidium@5587: treetype = (TreeType)p1; tron@3441: if (treetype == TREE_INVALID) { tron@2981: treetype = GetRandomTreeType(tile, GB(Random(), 24, 8)); tron@3441: if (treetype == TREE_INVALID) treetype = TREE_CACTUS; tron@1286: } tron@1286: tron@3079: growth = _game_mode == GM_EDITOR ? 3 : 0; tron@2981: switch (GetClearGround(tile)) { tron@3447: case CLEAR_ROUGH: MakeTree(tile, treetype, 0, growth, TREE_GROUND_ROUGH, 0); break; tron@3447: case CLEAR_SNOW: MakeTree(tile, treetype, 0, growth, TREE_GROUND_SNOW_DESERT, GetClearDensity(tile)); break; tron@3447: default: MakeTree(tile, treetype, 0, growth, TREE_GROUND_GRASS, 0); break; tron@1286: } tron@3003: MarkTileDirtyByTile(tile); tron@1286: tron@3441: if (_game_mode == GM_EDITOR && IS_INT_INSIDE(treetype, TREE_RAINFOREST, TREE_CACTUS)) belugas@3379: SetTropicZone(tile, TROPICZONE_RAINFOREST); truelight@0: } rubidium@6950: cost.AddCost(_price.build_trees); tron@1286: break; tron@1286: tron@1286: default: tron@3183: msg = STR_2804_SITE_UNSUITABLE; tron@1286: break; truelight@0: } truelight@0: } truelight@0: } truelight@193: rubidium@6950: if (cost.GetCost() == 0) { tron@3183: return_cmd_error(msg); tron@3183: } else { tron@3183: return cost; tron@3183: } truelight@0: } truelight@0: rubidium@6248: struct TreeListEnt { peter1138@5668: SpriteID image; peter1138@5668: SpriteID pal; rubidium@6491: byte x, y; rubidium@6248: }; truelight@0: truelight@0: static void DrawTile_Trees(TileInfo *ti) truelight@0: { peter1138@5668: const PalSpriteID *s; tron@2654: const TreePos* d; truelight@0: byte z; truelight@0: tron@2981: switch (GetTreeGround(ti->tile)) { tron@3441: case TREE_GROUND_GRASS: DrawClearLandTile(ti, 3); break; tron@3441: case TREE_GROUND_ROUGH: DrawHillyLandTile(ti); break; peter1138@5668: default: DrawGroundSprite(_tree_sprites_1[GetTreeDensity(ti->tile)] + _tileh_to_sprite[ti->tileh], PAL_NONE); break; truelight@0: } truelight@0: tron@2220: DrawClearLandFence(ti); truelight@0: truelight@0: z = ti->z; tron@3636: if (ti->tileh != SLOPE_FLAT) { truelight@0: z += 4; tron@3636: if (IsSteepSlope(ti->tileh)) z += 4; truelight@0: } truelight@0: truelight@0: { truelight@0: uint16 tmp = ti->x; tron@959: uint index; truelight@0: tron@2088: tmp = ROR(tmp, 2); truelight@0: tmp -= ti->y; tron@2088: tmp = ROR(tmp, 3); truelight@0: tmp -= ti->x; tron@2088: tmp = ROR(tmp, 1); truelight@0: tmp += ti->y; truelight@0: tron@2088: d = _tree_layout_xy[GB(tmp, 4, 2)]; truelight@0: tron@2981: index = GB(tmp, 6, 2) + (GetTreeType(ti->tile) << 2); truelight@193: truelight@0: /* different tree styles above one of the grounds */ tron@3441: if (GetTreeGround(ti->tile) == TREE_GROUND_SNOW_DESERT && tron@2981: GetTreeDensity(ti->tile) >= 2 && tron@3441: IS_INT_INSIDE(index, TREE_SUB_ARCTIC << 2, TREE_RAINFOREST << 2)) { tron@3441: index += 164 - (TREE_SUB_ARCTIC << 2); tron@2981: } truelight@193: truelight@193: assert(index < lengthof(_tree_layout_sprite)); truelight@0: s = _tree_layout_sprite[index]; truelight@0: } truelight@0: truelight@0: StartSpriteCombine(); truelight@0: peter1138@6427: if (!HASBIT(_transparent_opt, TO_TREES) || !_patches.invisible_trees) { tron@2088: TreeListEnt te[4]; tron@2088: uint i; truelight@0: truelight@0: /* put the trees to draw in a list */ tron@3271: i = GetTreeCount(ti->tile) + 1; truelight@0: do { peter1138@5668: SpriteID image = s[0].sprite + (--i == 0 ? GetTreeGrowth(ti->tile) : 3); rubidium@7333: SpriteID pal = s[0].pal; rubidium@7333: truelight@0: te[i].image = image; peter1138@5668: te[i].pal = pal; tron@2654: te[i].x = d->x; tron@2654: te[i].y = d->y; truelight@0: s++; tron@2654: d++; truelight@0: } while (i); truelight@0: truelight@0: /* draw them in a sorted way */ tron@2952: for (;;) { truelight@0: byte min = 0xFF; truelight@0: TreeListEnt *tep = NULL; truelight@0: tron@3271: i = GetTreeCount(ti->tile) + 1; truelight@0: do { tron@2644: if (te[--i].image != 0 && te[i].x + te[i].y < min) { truelight@0: min = te[i].x + te[i].y; truelight@0: tep = &te[i]; truelight@0: } truelight@0: } while (i); truelight@0: tron@2088: if (tep == NULL) break; truelight@0: rubidium@7333: AddSortableSpriteToDraw(tep->image, tep->pal, ti->x + tep->x, ti->y + tep->y, 5, 5, 0x10, z, HASBIT(_transparent_opt, TO_TREES)); truelight@0: tep->image = 0; truelight@0: } truelight@0: } truelight@0: truelight@0: EndSpriteCombine(); truelight@0: } truelight@0: truelight@0: tron@4231: static uint GetSlopeZ_Trees(TileIndex tile, uint x, uint y) tron@2537: { tron@4231: uint z; rubidium@5587: Slope tileh = GetTileSlope(tile, &z); tron@4231: tron@4231: return z + GetPartialZ(x & 0xF, y & 0xF, tileh); truelight@0: } truelight@0: rubidium@7335: static Foundation GetFoundation_Trees(TileIndex tile, Slope tileh) tron@2548: { rubidium@7335: return FOUNDATION_NONE; dominik@39: } dominik@39: rubidium@6943: static CommandCost ClearTile_Trees(TileIndex tile, byte flags) tron@1977: { tron@2243: uint num; truelight@0: Darkvater@4850: if ((flags & DC_EXEC) && IsValidPlayer(_current_player)) { truelight@0: Town *t = ClosestTownFromTile(tile, _patches.dist_local_authority); truelight@193: if (t != NULL) celestar@1005: ChangeTownRating(t, RATING_TREE_DOWN_STEP, RATING_TREE_MINIMUM); truelight@0: } truelight@0: tron@2981: num = GetTreeCount(tile) + 1; tron@3441: if (IS_INT_INSIDE(GetTreeType(tile), TREE_RAINFOREST, TREE_CACTUS)) num *= 4; truelight@0: tron@2243: if (flags & DC_EXEC) DoClearSquare(tile); truelight@0: rubidium@6950: return CommandCost(num * _price.remove_trees); truelight@0: } truelight@0: tron@1977: static void GetAcceptedCargo_Trees(TileIndex tile, AcceptedCargo ac) truelight@0: { truelight@0: /* not used */ truelight@0: } truelight@0: tron@1977: static void GetTileDesc_Trees(TileIndex tile, TileDesc *td) truelight@0: { tron@2981: TreeType tt = GetTreeType(tile); tron@2981: tron@3441: if (IS_INT_INSIDE(tt, TREE_RAINFOREST, TREE_CACTUS)) { tron@2981: td->str = STR_280F_RAINFOREST; tron@3441: } else if (tt == TREE_CACTUS) { tron@2981: td->str = STR_2810_CACTUS_PLANTS; tron@2981: } else { tron@2981: td->str = STR_280E_TREES; tron@2981: } truelight@0: tron@1901: td->owner = GetTileOwner(tile); truelight@0: } truelight@0: tron@1977: static void AnimateTile_Trees(TileIndex tile) truelight@0: { truelight@0: /* not used */ truelight@0: } truelight@0: tron@1977: static void TileLoopTreesDesert(TileIndex tile) truelight@0: { belugas@3379: switch (GetTropicZone(tile)) { belugas@3379: case TROPICZONE_DESERT: tron@3441: if (GetTreeGround(tile) != TREE_GROUND_SNOW_DESERT) { tron@3441: SetTreeGroundDensity(tile, TREE_GROUND_SNOW_DESERT, 3); tron@2981: MarkTileDirtyByTile(tile); tron@2981: } tron@2981: break; tron@2243: belugas@3379: case TROPICZONE_RAINFOREST: { tron@2981: static const SoundFx forest_sounds[] = { tron@2981: SND_42_LOON_BIRD, tron@2981: SND_43_LION, tron@2981: SND_44_MONKEYS, tron@2981: SND_48_DISTANT_BIRD tron@2981: }; tron@2981: uint32 r = Random(); truelight@0: tron@2981: if (CHANCE16I(1, 200, r)) SndPlayTileFx(forest_sounds[GB(r, 16, 2)], tile); tron@2981: break; truelight@0: } belugas@3379: belugas@3379: default: break; truelight@0: } truelight@0: } truelight@0: tron@1977: static void TileLoopTreesAlps(TileIndex tile) truelight@0: { maedhros@6343: int k = GetTileZ(tile) - GetSnowLine() + TILE_HEIGHT; truelight@0: tron@4157: if (k < 0) { tron@3441: if (GetTreeGround(tile) != TREE_GROUND_SNOW_DESERT) return; tron@3441: SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 0); truelight@0: } else { tron@4157: uint density = min((uint)k / TILE_HEIGHT, 3); tron@2981: tron@3441: if (GetTreeGround(tile) != TREE_GROUND_SNOW_DESERT || tron@3441: GetTreeDensity(tile) != density) { tron@3441: SetTreeGroundDensity(tile, TREE_GROUND_SNOW_DESERT, density); tron@2981: } else { tron@2981: if (GetTreeDensity(tile) == 3) { tron@2981: uint32 r = Random(); tron@2981: if (CHANCE16I(1, 200, r)) { tron@2981: SndPlayTileFx((r & 0x80000000) ? SND_39_HEAVY_WIND : SND_34_WIND, tile); tron@2981: } truelight@0: } truelight@0: return; truelight@0: } truelight@0: } truelight@0: MarkTileDirtyByTile(tile); truelight@0: } truelight@0: tron@1977: static void TileLoop_Trees(TileIndex tile) truelight@0: { tron@2981: switch (_opt.landscape) { belugas@6357: case LT_TROPIC: TileLoopTreesDesert(tile); break; belugas@6357: case LT_ARCTIC: TileLoopTreesAlps(tile); break; truelight@0: } truelight@0: truelight@0: TileLoopClearHelper(tile); truelight@0: tron@2981: if (GetTreeCounter(tile) < 15) { tron@2981: AddTreeCounter(tile, 1); tron@2981: return; tron@2981: } tron@2981: SetTreeCounter(tile, 0); truelight@193: tron@2981: switch (GetTreeGrowth(tile)) { tron@2981: case 3: /* regular sized tree */ belugas@6357: if (_opt.landscape == LT_TROPIC && tron@3441: GetTreeType(tile) != TREE_CACTUS && belugas@3379: GetTropicZone(tile) == TROPICZONE_DESERT) { tron@2981: AddTreeGrowth(tile, 1); tron@2981: } else { tron@2981: switch (GB(Random(), 0, 3)) { tron@2981: case 0: /* start destructing */ tron@2981: AddTreeGrowth(tile, 1); tron@2955: break; tron@2955: tron@2981: case 1: /* add a tree */ tron@2981: if (GetTreeCount(tile) < 3) { tron@2981: AddTreeCount(tile, 1); tron@2981: SetTreeGrowth(tile, 0); tron@2981: break; tron@2981: } tron@2981: /* FALL THROUGH */ truelight@0: tron@2981: case 2: { /* add a neighbouring tree */ tron@2981: TreeType treetype = GetTreeType(tile); truelight@0: rubidium@7317: tile += TileOffsByDir((Direction)(Random() & 7)); truelight@0: celestar@5385: if (!IsTileType(tile, MP_CLEAR) || IsBridgeAbove(tile)) return; tron@2981: tron@2981: switch (GetClearGround(tile)) { tron@3447: case CLEAR_GRASS: tron@2981: if (GetClearDensity(tile) != 3) return; tron@3441: MakeTree(tile, treetype, 0, 0, TREE_GROUND_GRASS, 0); tron@2981: break; tron@2981: tron@3447: case CLEAR_ROUGH: MakeTree(tile, treetype, 0, 0, TREE_GROUND_ROUGH, 0); break; tron@3447: case CLEAR_SNOW: MakeTree(tile, treetype, 0, 0, TREE_GROUND_SNOW_DESERT, GetClearDensity(tile)); break; tron@2981: default: return; tron@2981: } tron@2981: break; tron@2981: } tron@2981: tron@2981: default: tron@2981: return; tron@2981: } truelight@0: } tron@2981: break; tron@2981: tron@2981: case 6: /* final stage of tree destruction */ tron@2981: if (GetTreeCount(tile) > 0) { tron@2981: /* more than one tree, delete it */ tron@2981: AddTreeCount(tile, -1); tron@2981: SetTreeGrowth(tile, 3); tron@2981: } else { tron@2981: /* just one tree, change type into MP_CLEAR */ tron@2981: switch (GetTreeGround(tile)) { tron@3447: case TREE_GROUND_GRASS: MakeClear(tile, CLEAR_GRASS, 3); break; tron@3447: case TREE_GROUND_ROUGH: MakeClear(tile, CLEAR_ROUGH, 3); break; tron@3447: default: MakeClear(tile, CLEAR_SNOW, GetTreeDensity(tile)); break; tron@2981: } truelight@0: } tron@2981: break; tron@2981: tron@2981: default: tron@2981: AddTreeGrowth(tile, 1); tron@2981: break; truelight@0: } truelight@0: truelight@0: MarkTileDirtyByTile(tile); truelight@0: } truelight@0: rubidium@6247: void OnTick_Trees() truelight@0: { truelight@0: uint32 r; tron@1977: TileIndex tile; tron@2955: ClearGround ct; tron@3017: TreeType tree; truelight@0: truelight@0: /* place a tree at a random rainforest spot */ belugas@6357: if (_opt.landscape == LT_TROPIC && belugas@3379: (r = Random(), tile = RandomTileSeed(r), GetTropicZone(tile) == TROPICZONE_RAINFOREST) && tron@1035: IsTileType(tile, MP_CLEAR) && celestar@5385: !IsBridgeAbove(tile) && tron@3447: (ct = GetClearGround(tile), ct == CLEAR_GRASS || ct == CLEAR_ROUGH) && tron@3441: (tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) { tron@3447: MakeTree(tile, tree, 0, 0, ct == CLEAR_ROUGH ? TREE_GROUND_ROUGH : TREE_GROUND_GRASS, 0); truelight@0: } truelight@0: belugas@6422: /* byte underflow */ tron@2088: if (--_trees_tick_ctr != 0) return; truelight@193: truelight@0: /* place a tree at a random spot */ truelight@0: r = Random(); truelight@0: tile = TILE_MASK(r); tron@1035: if (IsTileType(tile, MP_CLEAR) && celestar@5385: !IsBridgeAbove(tile) && tron@3447: (ct = GetClearGround(tile), ct == CLEAR_GRASS || ct == CLEAR_ROUGH || ct == CLEAR_SNOW) && tron@3441: (tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) { tron@2955: switch (ct) { tron@3447: case CLEAR_GRASS: MakeTree(tile, tree, 0, 0, TREE_GROUND_GRASS, 0); break; tron@3447: case CLEAR_ROUGH: MakeTree(tile, tree, 0, 0, TREE_GROUND_ROUGH, 0); break; tron@3441: default: MakeTree(tile, tree, 0, 0, TREE_GROUND_SNOW_DESERT, GetClearDensity(tile)); break; truelight@0: } truelight@0: } truelight@0: } truelight@0: tron@1977: static void ClickTile_Trees(TileIndex tile) truelight@0: { truelight@0: /* not used */ truelight@0: } truelight@0: rubidium@6683: static uint32 GetTileTrackStatus_Trees(TileIndex tile, TransportType mode, uint sub_mode) truelight@0: { truelight@0: return 0; truelight@0: } truelight@0: Darkvater@2436: static void ChangeTileOwner_Trees(TileIndex tile, PlayerID old_player, PlayerID new_player) truelight@0: { truelight@0: /* not used */ truelight@0: } truelight@0: rubidium@6247: void InitializeTrees() truelight@0: { truelight@0: _trees_tick_ctr = 0; truelight@0: } truelight@0: rubidium@7494: static CommandCost TerraformTile_Trees(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new) rubidium@7494: { rubidium@7494: return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); rubidium@7494: } rubidium@7494: truelight@0: rubidium@5587: extern const TileTypeProcs _tile_type_trees_procs = { rubidium@4344: DrawTile_Trees, /* draw_tile_proc */ rubidium@4344: GetSlopeZ_Trees, /* get_slope_z_proc */ rubidium@4344: ClearTile_Trees, /* clear_tile_proc */ rubidium@4344: GetAcceptedCargo_Trees, /* get_accepted_cargo_proc */ rubidium@4344: GetTileDesc_Trees, /* get_tile_desc_proc */ rubidium@4344: GetTileTrackStatus_Trees, /* get_tile_track_status_proc */ rubidium@4344: ClickTile_Trees, /* click_tile_proc */ rubidium@4344: AnimateTile_Trees, /* animate_tile_proc */ rubidium@4344: TileLoop_Trees, /* tile_loop_clear */ rubidium@4344: ChangeTileOwner_Trees, /* change_tile_owner_clear */ rubidium@4344: NULL, /* get_produced_cargo_proc */ rubidium@4344: NULL, /* vehicle_enter_tile_proc */ rubidium@7335: GetFoundation_Trees, /* get_foundation_proc */ rubidium@7494: TerraformTile_Trees, /* terraform_tile_proc */ truelight@0: };