18 #include "transparency.h" |
18 #include "transparency.h" |
19 #include "functions.h" |
19 #include "functions.h" |
20 #include "player_func.h" |
20 #include "player_func.h" |
21 #include "sound_func.h" |
21 #include "sound_func.h" |
22 #include "settings_type.h" |
22 #include "settings_type.h" |
|
23 #include "water_map.h" |
|
24 #include "water.h" |
23 |
25 |
24 #include "table/strings.h" |
26 #include "table/strings.h" |
25 #include "table/sprites.h" |
27 #include "table/sprites.h" |
26 #include "table/tree_land.h" |
28 #include "table/tree_land.h" |
27 |
29 |
35 TP_ORIGINAL, ///< The original algorithm |
37 TP_ORIGINAL, ///< The original algorithm |
36 TP_IMPROVED, ///< A 'improved' algorithm |
38 TP_IMPROVED, ///< A 'improved' algorithm |
37 }; |
39 }; |
38 |
40 |
39 /** |
41 /** |
|
42 * Tests if a tile can be converted to MP_TREES |
|
43 * This is true for clear ground without farms or rocks. |
|
44 * |
|
45 * @param tile the tile of interest |
|
46 * @param allow_desert Allow planting trees on CLEAR_DESERT? |
|
47 * @return true if trees can be built. |
|
48 */ |
|
49 static bool CanPlantTreesOnTile(TileIndex tile, bool allow_desert) |
|
50 { |
|
51 switch (GetTileType(tile)) { |
|
52 case MP_WATER: |
|
53 return !IsBridgeAbove(tile) && IsCoast(tile) && !IsSlopeWithOneCornerRaised(GetTileSlope(tile, NULL)); |
|
54 |
|
55 case MP_CLEAR: |
|
56 return !IsBridgeAbove(tile) && !IsClearGround(tile, CLEAR_FIELDS) && !IsClearGround(tile, CLEAR_ROCKS) && |
|
57 (allow_desert || !IsClearGround(tile, CLEAR_DESERT)); |
|
58 |
|
59 default: return false; |
|
60 } |
|
61 } |
|
62 |
|
63 /** |
|
64 * Creates a tree tile |
|
65 * Ground type and density is preserved. |
|
66 * |
|
67 * @pre the tile must be suitable for trees. |
|
68 * |
|
69 * @param tile where to plant the trees. |
|
70 * @param type The type of the tree |
|
71 * @param count the number of trees (minus 1) |
|
72 * @param growth the growth status |
|
73 */ |
|
74 static void PlantTreesOnTile(TileIndex tile, TreeType treetype, uint count, uint growth) |
|
75 { |
|
76 assert(treetype != TREE_INVALID); |
|
77 assert(CanPlantTreesOnTile(tile, true)); |
|
78 |
|
79 TreeGround ground; |
|
80 uint density = 3; |
|
81 |
|
82 switch (GetTileType(tile)) { |
|
83 case MP_WATER: |
|
84 ground = TREE_GROUND_SHORE; |
|
85 break; |
|
86 |
|
87 case MP_CLEAR: |
|
88 switch (GetClearGround(tile)) { |
|
89 case CLEAR_GRASS: ground = TREE_GROUND_GRASS; density = GetClearDensity(tile); break; |
|
90 case CLEAR_ROUGH: ground = TREE_GROUND_ROUGH; break; |
|
91 default: ground = TREE_GROUND_SNOW_DESERT; density = GetClearDensity(tile); break; |
|
92 } |
|
93 break; |
|
94 |
|
95 default: NOT_REACHED(); |
|
96 } |
|
97 |
|
98 MakeTree(tile, treetype, count, growth, ground, density); |
|
99 } |
|
100 |
|
101 /** |
40 * Get a random TreeType for the given tile based on a given seed |
102 * Get a random TreeType for the given tile based on a given seed |
41 * |
103 * |
42 * This function returns a random TreeType which can be placed on the given tile. |
104 * This function returns a random TreeType which can be placed on the given tile. |
43 * The seed for randomness must be less or equal 256, use #GB on the value of Random() |
105 * The seed for randomness must be less or equal 256, use #GB on the value of Random() |
44 * to get such a value. |
106 * to get such a value. |
80 static void PlaceTree(TileIndex tile, uint32 r) |
142 static void PlaceTree(TileIndex tile, uint32 r) |
81 { |
143 { |
82 TreeType tree = GetRandomTreeType(tile, GB(r, 24, 8)); |
144 TreeType tree = GetRandomTreeType(tile, GB(r, 24, 8)); |
83 |
145 |
84 if (tree != TREE_INVALID) { |
146 if (tree != TREE_INVALID) { |
85 MakeTree(tile, tree, GB(r, 22, 2), min(GB(r, 16, 3), 6), TREE_GROUND_GRASS, 0); |
147 PlantTreesOnTile(tile, tree, GB(r, 22, 2), min(GB(r, 16, 3), 6)); |
86 |
148 |
87 /* above snowline? */ |
149 /* Rerandomize ground, if neither snow nor shore */ |
88 if (_opt.landscape == LT_ARCTIC && GetTileZ(tile) > GetSnowLine()) { |
150 TreeGround ground = GetTreeGround(tile); |
89 SetTreeGroundDensity(tile, TREE_GROUND_SNOW_DESERT, 3); |
151 if (ground != TREE_GROUND_SNOW_DESERT && ground != TREE_GROUND_SHORE) { |
90 SetTreeCounter(tile, (TreeGround)GB(r, 24, 3)); |
|
91 } else { |
|
92 SetTreeGroundDensity(tile, (TreeGround)GB(r, 28, 1), 3); |
152 SetTreeGroundDensity(tile, (TreeGround)GB(r, 28, 1), 3); |
93 SetTreeCounter(tile, (TreeGround)GB(r, 24, 4)); |
153 } |
94 } |
154 |
|
155 /* Set the counter to a random start value */ |
|
156 SetTreeCounter(tile, (TreeGround)GB(r, 24, 4)); |
95 } |
157 } |
96 } |
158 } |
97 |
159 |
98 /** |
160 /** |
99 * Place some amount of trees around a given tile. |
161 * Place some amount of trees around a given tile. |
113 int x = GB(r, 0, 5) - 16; |
175 int x = GB(r, 0, 5) - 16; |
114 int y = GB(r, 8, 5) - 16; |
176 int y = GB(r, 8, 5) - 16; |
115 uint dist = abs(x) + abs(y); |
177 uint dist = abs(x) + abs(y); |
116 TileIndex cur_tile = TILE_MASK(tile + TileDiffXY(x, y)); |
178 TileIndex cur_tile = TILE_MASK(tile + TileDiffXY(x, y)); |
117 |
179 |
118 if (dist <= 13 && |
180 if (dist <= 13 && CanPlantTreesOnTile(cur_tile, true)) { |
119 IsTileType(cur_tile, MP_CLEAR) && |
|
120 !IsBridgeAbove(cur_tile) && |
|
121 !IsClearGround(cur_tile, CLEAR_FIELDS) && |
|
122 !IsClearGround(cur_tile, CLEAR_ROCKS)) { |
|
123 PlaceTree(cur_tile, r); |
181 PlaceTree(cur_tile, r); |
124 } |
182 } |
125 } |
183 } |
126 } |
184 } |
127 |
185 |
159 |
217 |
160 /* Keep in range of the existing tree */ |
218 /* Keep in range of the existing tree */ |
161 if (abs(x) + abs(y) > 16) continue; |
219 if (abs(x) + abs(y) > 16) continue; |
162 |
220 |
163 /* Clear tile, no farm-tiles or rocks */ |
221 /* Clear tile, no farm-tiles or rocks */ |
164 if (!IsTileType(cur_tile, MP_CLEAR) || |
222 if (!CanPlantTreesOnTile(cur_tile, true)) continue; |
165 IsClearGround(cur_tile, CLEAR_FIELDS) || |
|
166 IsClearGround(cur_tile, CLEAR_ROCKS)) |
|
167 continue; |
|
168 |
223 |
169 /* Not too much height difference */ |
224 /* Not too much height difference */ |
170 if (Delta(GetTileZ(cur_tile), height) > 2) continue; |
225 if (Delta(GetTileZ(cur_tile), height) > 2) continue; |
171 |
226 |
172 /* Place one tree and quit */ |
227 /* Place one tree and quit */ |
189 uint32 r = Random(); |
244 uint32 r = Random(); |
190 TileIndex tile = RandomTileSeed(r); |
245 TileIndex tile = RandomTileSeed(r); |
191 |
246 |
192 IncreaseGeneratingWorldProgress(GWP_TREE); |
247 IncreaseGeneratingWorldProgress(GWP_TREE); |
193 |
248 |
194 if (IsTileType(tile, MP_CLEAR) && |
249 if (CanPlantTreesOnTile(tile, true)) { |
195 !IsBridgeAbove(tile) && |
|
196 !IsClearGround(tile, CLEAR_FIELDS) && |
|
197 !IsClearGround(tile, CLEAR_ROCKS)) { |
|
198 PlaceTree(tile, r); |
250 PlaceTree(tile, r); |
199 if (_patches.tree_placer != TP_IMPROVED) continue; |
251 if (_patches.tree_placer != TP_IMPROVED) continue; |
200 |
252 |
201 /* Place a number of trees based on the tile height. |
253 /* Place a number of trees based on the tile height. |
202 * This gives a cool effect of multiple trees close together. |
254 * This gives a cool effect of multiple trees close together. |
311 /* 2x as expensive to add more trees to an existing tile */ |
360 /* 2x as expensive to add more trees to an existing tile */ |
312 cost.AddCost(_price.build_trees * 2); |
361 cost.AddCost(_price.build_trees * 2); |
313 break; |
362 break; |
314 |
363 |
315 case MP_WATER: |
364 case MP_WATER: |
316 msg = STR_3807_CAN_T_BUILD_ON_WATER; |
365 if (!IsCoast(tile) || IsSlopeWithOneCornerRaised(GetTileSlope(tile, NULL))) { |
317 continue; |
366 msg = STR_3807_CAN_T_BUILD_ON_WATER; |
318 break; |
367 continue; |
319 |
368 } |
|
369 /* FALL THROUGH */ |
320 case MP_CLEAR: |
370 case MP_CLEAR: |
321 if (!IsTileOwner(tile, OWNER_NONE) || |
371 if (IsBridgeAbove(tile)) { |
322 IsBridgeAbove(tile)) { |
|
323 msg = STR_2804_SITE_UNSUITABLE; |
372 msg = STR_2804_SITE_UNSUITABLE; |
324 continue; |
373 continue; |
325 } |
374 } |
326 |
375 |
327 switch (GetClearGround(tile)) { |
376 if (IsTileType(tile, MP_CLEAR)) { |
328 case CLEAR_FIELDS: cost.AddCost(_price.clear_fields); break; |
377 /* Remove fields or rocks. Note that the ground will get barrened */ |
329 case CLEAR_ROCKS: cost.AddCost(_price.clear_rocks); break; |
378 switch (GetClearGround(tile)) { |
330 default: break; |
379 case CLEAR_FIELDS: |
|
380 case CLEAR_ROCKS: { |
|
381 CommandCost ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); |
|
382 if (CmdFailed(ret)) return ret; |
|
383 cost.AddCost(ret); |
|
384 break; |
|
385 } |
|
386 |
|
387 default: break; |
|
388 } |
331 } |
389 } |
332 |
390 |
333 if (_game_mode != GM_EDITOR && IsValidPlayer(_current_player)) { |
391 if (_game_mode != GM_EDITOR && IsValidPlayer(_current_player)) { |
334 Town *t = ClosestTownFromTile(tile, _patches.dist_local_authority); |
392 Town *t = ClosestTownFromTile(tile, _patches.dist_local_authority); |
335 if (t != NULL) ChangeTownRating(t, RATING_TREE_UP_STEP, RATING_TREE_MAXIMUM); |
393 if (t != NULL) ChangeTownRating(t, RATING_TREE_UP_STEP, RATING_TREE_MAXIMUM); |
336 } |
394 } |
337 |
395 |
338 if (flags & DC_EXEC) { |
396 if (flags & DC_EXEC) { |
339 TreeType treetype; |
397 TreeType treetype; |
340 uint growth; |
|
341 |
398 |
342 treetype = (TreeType)p1; |
399 treetype = (TreeType)p1; |
343 if (treetype == TREE_INVALID) { |
400 if (treetype == TREE_INVALID) { |
344 treetype = GetRandomTreeType(tile, GB(Random(), 24, 8)); |
401 treetype = GetRandomTreeType(tile, GB(Random(), 24, 8)); |
345 if (treetype == TREE_INVALID) treetype = TREE_CACTUS; |
402 if (treetype == TREE_INVALID) treetype = TREE_CACTUS; |
346 } |
403 } |
347 |
404 |
348 growth = _game_mode == GM_EDITOR ? 3 : 0; |
405 /* Plant full grown trees in scenario editor */ |
349 switch (GetClearGround(tile)) { |
406 PlantTreesOnTile(tile, treetype, 0, _game_mode == GM_EDITOR ? 3 : 0); |
350 case CLEAR_ROUGH: MakeTree(tile, treetype, 0, growth, TREE_GROUND_ROUGH, 3); break; |
|
351 case CLEAR_SNOW: |
|
352 case CLEAR_DESERT: MakeTree(tile, treetype, 0, growth, TREE_GROUND_SNOW_DESERT, GetClearDensity(tile)); break; |
|
353 default: MakeTree(tile, treetype, 0, growth, TREE_GROUND_GRASS, GetClearDensity(tile)); break; |
|
354 } |
|
355 MarkTileDirtyByTile(tile); |
407 MarkTileDirtyByTile(tile); |
356 |
408 |
|
409 /* When planting rainforest-trees, set tropiczone to rainforest in editor. */ |
357 if (_game_mode == GM_EDITOR && IsInsideMM(treetype, TREE_RAINFOREST, TREE_CACTUS)) |
410 if (_game_mode == GM_EDITOR && IsInsideMM(treetype, TREE_RAINFOREST, TREE_CACTUS)) |
358 SetTropicZone(tile, TROPICZONE_RAINFOREST); |
411 SetTropicZone(tile, TROPICZONE_RAINFOREST); |
359 } |
412 } |
360 cost.AddCost(_price.build_trees); |
413 cost.AddCost(_price.build_trees); |
361 break; |
414 break; |
576 MarkTileDirtyByTile(tile); |
631 MarkTileDirtyByTile(tile); |
577 } |
632 } |
578 |
633 |
579 static void TileLoop_Trees(TileIndex tile) |
634 static void TileLoop_Trees(TileIndex tile) |
580 { |
635 { |
581 switch (_opt.landscape) { |
636 if (GetTreeGround(tile) == TREE_GROUND_SHORE) { |
582 case LT_TROPIC: TileLoopTreesDesert(tile); break; |
637 TileLoop_Water(tile); |
583 case LT_ARCTIC: TileLoopTreesAlps(tile); break; |
638 } else { |
|
639 switch (_opt.landscape) { |
|
640 case LT_TROPIC: TileLoopTreesDesert(tile); break; |
|
641 case LT_ARCTIC: TileLoopTreesAlps(tile); break; |
|
642 } |
584 } |
643 } |
585 |
644 |
586 TileLoopClearHelper(tile); |
645 TileLoopClearHelper(tile); |
587 |
646 |
588 uint treeCounter = GetTreeCounter(tile); |
647 uint treeCounter = GetTreeCounter(tile); |
624 case 2: { /* add a neighbouring tree */ |
683 case 2: { /* add a neighbouring tree */ |
625 TreeType treetype = GetTreeType(tile); |
684 TreeType treetype = GetTreeType(tile); |
626 |
685 |
627 tile += TileOffsByDir((Direction)(Random() & 7)); |
686 tile += TileOffsByDir((Direction)(Random() & 7)); |
628 |
687 |
629 if (!IsTileType(tile, MP_CLEAR) || IsBridgeAbove(tile)) return; |
688 /* Cacti don't spread */ |
630 |
689 if (!CanPlantTreesOnTile(tile, false)) return; |
631 switch (GetClearGround(tile)) { |
690 |
632 case CLEAR_GRASS: |
691 /* Don't plant trees, if ground was freshly cleared */ |
633 if (GetClearDensity(tile) != 3) return; |
692 if (IsTileType(tile, MP_CLEAR) && GetClearGround(tile) == CLEAR_GRASS && GetClearDensity(tile) != 3) return; |
634 MakeTree(tile, treetype, 0, 0, TREE_GROUND_GRASS, 3); |
693 |
635 break; |
694 PlantTreesOnTile(tile, treetype, 0, 0); |
636 |
695 |
637 case CLEAR_ROUGH: MakeTree(tile, treetype, 0, 0, TREE_GROUND_ROUGH, 3); break; |
|
638 case CLEAR_DESERT: return; // Cacti don't spread |
|
639 case CLEAR_SNOW: MakeTree(tile, treetype, 0, 0, TREE_GROUND_SNOW_DESERT, GetClearDensity(tile)); break; |
|
640 default: return; |
|
641 } |
|
642 break; |
696 break; |
643 } |
697 } |
644 |
698 |
645 default: |
699 default: |
646 return; |
700 return; |
654 AddTreeCount(tile, -1); |
708 AddTreeCount(tile, -1); |
655 SetTreeGrowth(tile, 3); |
709 SetTreeGrowth(tile, 3); |
656 } else { |
710 } else { |
657 /* just one tree, change type into MP_CLEAR */ |
711 /* just one tree, change type into MP_CLEAR */ |
658 switch (GetTreeGround(tile)) { |
712 switch (GetTreeGround(tile)) { |
|
713 case TREE_GROUND_SHORE: MakeShore(tile); break; |
659 case TREE_GROUND_GRASS: MakeClear(tile, CLEAR_GRASS, GetTreeDensity(tile)); break; |
714 case TREE_GROUND_GRASS: MakeClear(tile, CLEAR_GRASS, GetTreeDensity(tile)); break; |
660 case TREE_GROUND_ROUGH: MakeClear(tile, CLEAR_ROUGH, 3); break; |
715 case TREE_GROUND_ROUGH: MakeClear(tile, CLEAR_ROUGH, 3); break; |
661 default: // snow or desert |
716 default: // snow or desert |
662 MakeClear(tile, _opt.landscape == LT_TROPIC ? CLEAR_DESERT : CLEAR_SNOW, GetTreeDensity(tile)); |
717 MakeClear(tile, _opt.landscape == LT_TROPIC ? CLEAR_DESERT : CLEAR_SNOW, GetTreeDensity(tile)); |
663 break; |
718 break; |
675 |
730 |
676 void OnTick_Trees() |
731 void OnTick_Trees() |
677 { |
732 { |
678 uint32 r; |
733 uint32 r; |
679 TileIndex tile; |
734 TileIndex tile; |
680 ClearGround ct; |
|
681 TreeType tree; |
735 TreeType tree; |
682 |
736 |
683 /* place a tree at a random rainforest spot */ |
737 /* place a tree at a random rainforest spot */ |
684 if (_opt.landscape == LT_TROPIC && |
738 if (_opt.landscape == LT_TROPIC && |
685 (r = Random(), tile = RandomTileSeed(r), GetTropicZone(tile) == TROPICZONE_RAINFOREST) && |
739 (r = Random(), tile = RandomTileSeed(r), GetTropicZone(tile) == TROPICZONE_RAINFOREST) && |
686 IsTileType(tile, MP_CLEAR) && |
740 CanPlantTreesOnTile(tile, false) && |
687 !IsBridgeAbove(tile) && |
|
688 (ct = GetClearGround(tile), ct == CLEAR_GRASS || ct == CLEAR_ROUGH) && |
|
689 (tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) { |
741 (tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) { |
690 MakeTree(tile, tree, 0, 0, ct == CLEAR_ROUGH ? TREE_GROUND_ROUGH : TREE_GROUND_GRASS, GetClearDensity(tile)); |
742 PlantTreesOnTile(tile, tree, 0, 0); |
691 } |
743 } |
692 |
744 |
693 /* byte underflow */ |
745 /* byte underflow */ |
694 if (--_trees_tick_ctr != 0) return; |
746 if (--_trees_tick_ctr != 0) return; |
695 |
747 |
696 /* place a tree at a random spot */ |
748 /* place a tree at a random spot */ |
697 r = Random(); |
749 r = Random(); |
698 tile = TILE_MASK(r); |
750 tile = TILE_MASK(r); |
699 if (IsTileType(tile, MP_CLEAR) && |
751 if (CanPlantTreesOnTile(tile, false) && (tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) { |
700 !IsBridgeAbove(tile) && |
752 PlantTreesOnTile(tile, tree, 0, 0); |
701 (ct = GetClearGround(tile), ct == CLEAR_GRASS || ct == CLEAR_ROUGH || ct == CLEAR_SNOW) && |
|
702 (tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) { |
|
703 switch (ct) { |
|
704 case CLEAR_GRASS: MakeTree(tile, tree, 0, 0, TREE_GROUND_GRASS, GetClearDensity(tile)); break; |
|
705 case CLEAR_ROUGH: MakeTree(tile, tree, 0, 0, TREE_GROUND_ROUGH, 3); break; |
|
706 default: MakeTree(tile, tree, 0, 0, TREE_GROUND_SNOW_DESERT, GetClearDensity(tile)); break; |
|
707 } |
|
708 } |
753 } |
709 } |
754 } |
710 |
755 |
711 static void ClickTile_Trees(TileIndex tile) |
756 static void ClickTile_Trees(TileIndex tile) |
712 { |
757 { |