OpenTTD Source 20260206-master-g4d4e37dbf1
tree_cmd.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "stdafx.h"
11#include "clear_map.h"
12#include "landscape.h"
13#include "tree_map.h"
14#include "viewport_func.h"
15#include "command_func.h"
16#include "town.h"
17#include "genworld.h"
18#include "clear_func.h"
19#include "company_func.h"
20#include "sound_func.h"
21#include "water.h"
22#include "company_base.h"
24#include "core/random_func.hpp"
25#include "newgrf_generic.h"
27#include "tree_cmd.h"
28#include "landscape_cmd.h"
29
30#include "table/strings.h"
31#include "table/tree_land.h"
32#include "table/clear_land.h"
33
34#include "safeguards.h"
35
43
46
47static const uint16_t DEFAULT_TREE_STEPS = 1000;
48static const uint16_t DEFAULT_RAINFOREST_TREE_STEPS = 15000;
49static const uint16_t EDITOR_TREE_DIV = 5;
50
59static bool CanPlantTreesOnTile(TileIndex tile, bool allow_desert)
60{
61 switch (GetTileType(tile)) {
62 case TileType::Water:
63 return !IsBridgeAbove(tile) && IsCoast(tile) && !IsSlopeWithOneCornerRaised(GetTileSlope(tile));
64
65 case TileType::Clear:
67 (allow_desert || !IsClearGround(tile, ClearGround::Desert));
68
69 default: return false;
70 }
71}
72
79{
80 switch (clearground) {
83 default: return TreeGround::SnowOrDesert;
84 }
85}
86
98static void PlantTreesOnTile(TileIndex tile, TreeType treetype, uint count, TreeGrowthStage growth)
99{
100 assert(treetype != TREE_INVALID);
101 assert(CanPlantTreesOnTile(tile, true));
102
103 TreeGround ground;
104 uint density = 3;
105
106 switch (GetTileType(tile)) {
107 case TileType::Water:
108 ground = TreeGround::Shore;
110 break;
111
112 case TileType::Clear: {
113 ClearGround clearground = GetClearGround(tile);
114 if (IsSnowTile(tile)) {
116 } else {
117 ground = TreeGroundFromClearGround(clearground);
118 }
119 if (clearground != ClearGround::Rough) density = GetClearDensity(tile);
120 break;
121 }
122
123 default: NOT_REACHED();
124 }
125
126 MakeTree(tile, treetype, count, growth, ground, density);
127}
128
140static TreeType GetRandomTreeType(TileIndex tile, uint seed)
141{
142 switch (_settings_game.game_creation.landscape) {
144 return static_cast<TreeType>(seed * TREE_COUNT_TEMPERATE / 256 + TREE_TEMPERATE);
145
147 return static_cast<TreeType>(seed * TREE_COUNT_SUB_ARCTIC / 256 + TREE_SUB_ARCTIC);
148
150 switch (GetTropicZone(tile)) {
151 case TROPICZONE_NORMAL: return static_cast<TreeType>(seed * TREE_COUNT_SUB_TROPICAL / 256 + TREE_SUB_TROPICAL);
152 case TROPICZONE_DESERT: return static_cast<TreeType>((seed > 12) ? TREE_INVALID : TREE_CACTUS);
153 default: return static_cast<TreeType>(seed * TREE_COUNT_RAINFOREST / 256 + TREE_RAINFOREST);
154 }
155
156 default:
157 return static_cast<TreeType>(seed * TREE_COUNT_TOYLAND / 256 + TREE_TOYLAND);
158 }
159}
160
171void PlaceTree(TileIndex tile, uint32_t r, bool keep_density)
172{
173 TreeType tree = GetRandomTreeType(tile, GB(r, 24, 8));
174
175 if (tree != TREE_INVALID) {
176 PlantTreesOnTile(tile, tree, GB(r, 22, 2), static_cast<TreeGrowthStage>(std::min<uint8_t>(GB(r, 16, 3), 6)));
178
179 /* Maybe keep the existing ground density.*/
180 if (keep_density) return;
181
182 /* Rerandomize ground, if neither snow nor shore */
183 TreeGround ground = GetTreeGround(tile);
184 if (ground != TreeGround::SnowOrDesert && ground != TreeGround::RoughSnow && ground != TreeGround::Shore) {
185 SetTreeGroundDensity(tile, (TreeGround)GB(r, 28, 1), 3);
186 }
187 }
188}
189
191 int amplitude;
192 float phase;
193 int frequency;
194};
195
203static void CreateStarShapedPolygon(int radius, std::span<const BlobHarmonic> harmonics, std::span<Point> shape)
204{
205 float theta = 0;
206 float step = (M_PI * 2) / std::size(shape);
207
208 /* Divide a circle into a number of equally spaced divisions. */
209 for (Point &vertex : shape) {
210
211 /* Add up the values of each harmonic at this segment.*/
212 float deviation = std::accumulate(std::begin(harmonics), std::end(harmonics), 0.f, [theta](float d, const BlobHarmonic &harmonic) -> float {
213 return d + sinf((theta + harmonic.phase) * harmonic.frequency) * harmonic.amplitude;
214 });
215
216 /* Smooth out changes. */
217 float adjusted_radius = (radius / 2.f) + (deviation / 2);
218
219 /* Add to the final polygon. */
220 vertex.x = cosf(theta) * adjusted_radius;
221 vertex.y = sinf(theta) * adjusted_radius;
222
223 /* Proceed to the next segment. */
224 theta += step;
225 }
226}
227
234static void CreateRandomStarShapedPolygon(int radius, std::span<Point> shape)
235{
236 /* Valid values for the phase of blob harmonics are between 0 and Tau. we can get a value in the correct range
237 * from Random() by dividing the maximum possible value by the desired maximum, and then dividing the random
238 * value by the result. */
239 static constexpr float PHASE_DIVISOR = static_cast<float>(INT32_MAX / M_PI * 2);
240
241 /* These values are ones found in testing that result in suitable-looking polygons that did not self-intersect
242 * and fit within a square of radius * radius dimensions. */
243 std::initializer_list<BlobHarmonic> harmonics = {
244 {radius / 2, Random() / PHASE_DIVISOR, 1},
245 {radius / 4, Random() / PHASE_DIVISOR, 2},
246 {radius / 8, Random() / PHASE_DIVISOR, 3},
247 {radius / 16, Random() / PHASE_DIVISOR, 4},
248 };
249
250 CreateStarShapedPolygon(radius, harmonics, shape);
251}
252
262static bool IsPointInTriangle(int x, int y, const Point &v1, const Point &v2, const Point &v3)
263{
264 const int s = ((v1.x - v3.x) * (y - v3.y)) - ((v1.y - v3.y) * (x - v3.x));
265 const int t = ((v2.x - v1.x) * (y - v1.y)) - ((v2.y - v1.y) * (x - v1.x));
266
267 if ((s < 0) != (t < 0) && s != 0 && t != 0) return false;
268
269 const int d = (v3.x - v2.x) * (y - v2.y) - (v3.y - v2.y) * (x - v2.x);
270 return (d < 0) == (s + t <= 0);
271}
272
281static bool IsPointInStarShapedPolygon(int x, int y, std::span<Point> shape)
282{
283 for (auto it = std::begin(shape); it != std::end(shape); /* nothing */) {
284 const Point &v1 = *it;
285 ++it;
286 const Point &v2 = (it == std::end(shape)) ? shape.front() : *it;
287
288 if (IsPointInTriangle(x, y, v1, v2, {0, 0})) return true;
289 }
290
291 return false;
292}
293
300static void PlaceTreeGroups(uint num_groups)
301{
302 static constexpr uint GROVE_SEGMENTS = 16;
303 static constexpr uint GROVE_RADIUS = 16;
304
305 /* Shape in which trees may be contained. Array is here to reduce allocations. */
306 std::array<Point, GROVE_SEGMENTS> grove;
307
308 do {
309 TileIndex center_tile = RandomTile();
310
311 CreateRandomStarShapedPolygon(GROVE_RADIUS, grove);
312
313 for (uint i = 0; i < DEFAULT_TREE_STEPS; i++) {
315
316 uint32_t r = Random();
317 int x = GB(r, 0, 5) - GROVE_RADIUS;
318 int y = GB(r, 8, 5) - GROVE_RADIUS;
319 TileIndex cur_tile = TileAddWrap(center_tile, x, y);
320
321 if (cur_tile == INVALID_TILE) continue;
322 if (!CanPlantTreesOnTile(cur_tile, true)) continue;
323 if (!IsPointInStarShapedPolygon(x, y, grove)) continue;
324
325 PlaceTree(cur_tile, r);
326 }
327
328 } while (--num_groups);
329}
330
340static void PlaceTreeAtSameHeight(TileIndex tile, int height)
341{
342 for (uint i = 0; i < DEFAULT_TREE_STEPS; i++) {
343 uint32_t r = Random();
344 int x = GB(r, 0, 5) - 16;
345 int y = GB(r, 8, 5) - 16;
346 TileIndex cur_tile = TileAddWrap(tile, x, y);
347 if (cur_tile == INVALID_TILE) continue;
348
349 /* Keep in range of the existing tree */
350 if (abs(x) + abs(y) > 16) continue;
351
352 /* Clear tile, no farm-tiles or rocks */
353 if (!CanPlantTreesOnTile(cur_tile, true)) continue;
354
355 /* Not too much height difference */
356 if (Delta(GetTileZ(cur_tile), height) > 2) continue;
357
358 /* Place one tree and quit */
359 PlaceTree(cur_tile, r);
360 break;
361 }
362}
363
370{
371 int i, j, ht;
372 uint8_t max_height = _settings_game.construction.map_height_limit;
373
375 if (_game_mode == GM_EDITOR) i /= EDITOR_TREE_DIV;
376 do {
377 uint32_t r = Random();
378 TileIndex tile = RandomTileSeed(r);
379
381
382 if (CanPlantTreesOnTile(tile, true)) {
383 PlaceTree(tile, r);
384 if (_settings_game.game_creation.tree_placer != TreePlacer::Improved) continue;
385
386 /* Place a number of trees based on the tile height.
387 * This gives a cool effect of multiple trees close together.
388 * It is almost real life ;) */
389 ht = GetTileZ(tile);
390 /* The higher we get, the more trees we plant */
391 j = GetTileZ(tile) * 2;
392 /* Above snowline more trees! */
393 if (_settings_game.game_creation.landscape == LandscapeType::Arctic && ht > GetSnowLine()) j *= 3;
394 /* Scale generation by maximum map height. */
395 if (max_height > MAP_HEIGHT_LIMIT_ORIGINAL) j = j * MAP_HEIGHT_LIMIT_ORIGINAL / max_height;
396 while (j--) {
397 PlaceTreeAtSameHeight(tile, ht);
398 }
399 }
400 } while (--i);
401
402 /* place extra trees at rainforest area */
403 if (_settings_game.game_creation.landscape == LandscapeType::Tropic) {
405 if (_game_mode == GM_EDITOR) i /= EDITOR_TREE_DIV;
406
407 do {
408 uint32_t r = Random();
409 TileIndex tile = RandomTileSeed(r);
410
412
413 if (GetTropicZone(tile) == TROPICZONE_RAINFOREST && CanPlantTreesOnTile(tile, false)) {
414 PlaceTree(tile, r);
415 }
416 } while (--i);
417 }
418}
419
432uint PlaceTreeGroupAroundTile(TileIndex tile, TreeType treetype, uint radius, uint count, bool set_zone)
433{
434 assert(_game_mode == GM_EDITOR); // Due to InteractiveRandom being used in this function
435 assert(treetype < TREE_TOYLAND + TREE_COUNT_TOYLAND);
436 const bool allow_desert = treetype == TREE_CACTUS;
437 uint planted = 0;
438
439 for (; count > 0; count--) {
440 /* Simple quasi-normal distribution with range [-radius; radius) */
441 auto mkcoord = [&]() -> int32_t {
442 const uint32_t rand = InteractiveRandom();
443 const int32_t dist = GB<int32_t>(rand, 0, 8) + GB<int32_t>(rand, 8, 8) + GB<int32_t>(rand, 16, 8) + GB<int32_t>(rand, 24, 8);
444 const int32_t scu = dist * radius / 512;
445 return scu - radius;
446 };
447 const int32_t xofs = mkcoord();
448 const int32_t yofs = mkcoord();
449 const TileIndex tile_to_plant = TileAddWrap(tile, xofs, yofs);
450 if (tile_to_plant != INVALID_TILE) {
451 if (IsTileType(tile_to_plant, TileType::Trees) && GetTreeCount(tile_to_plant) < 4) {
452 AddTreeCount(tile_to_plant, 1);
454 MarkTileDirtyByTile(tile_to_plant, 0);
455 planted++;
456 } else if (CanPlantTreesOnTile(tile_to_plant, allow_desert)) {
457 PlantTreesOnTile(tile_to_plant, treetype, 0, TreeGrowthStage::Grown);
458 MarkTileDirtyByTile(tile_to_plant, 0);
459 planted++;
460 }
461 }
462 }
463
464 if (set_zone && IsInsideMM(treetype, TREE_RAINFOREST, TREE_CACTUS)) {
465 for (TileIndex t : TileArea(tile).Expand(radius)) {
466 if (GetTileType(t) != TileType::Void && DistanceSquare(tile, t) < radius * radius) SetTropicZone(t, TROPICZONE_RAINFOREST);
467 }
468 }
469
470 return planted;
471}
472
480{
481 uint i, total;
482
483 if (_settings_game.game_creation.tree_placer == TreePlacer::None) return;
484
485 switch (_settings_game.game_creation.tree_placer) {
486 case TreePlacer::Original: i = _settings_game.game_creation.landscape == LandscapeType::Arctic ? 15 : 6; break;
487 case TreePlacer::Improved: i = _settings_game.game_creation.landscape == LandscapeType::Arctic ? 4 : 2; break;
488 default: NOT_REACHED();
489 }
490
493 total *= i;
494 uint num_groups = (_settings_game.game_creation.landscape != LandscapeType::Toyland) ? Map::ScaleBySize(GB(Random(), 0, 5) + 25) : 0;
495 total += num_groups * DEFAULT_TREE_STEPS;
497
498 if (num_groups != 0) PlaceTreeGroups(num_groups);
499
500 for (; i != 0; i--) {
502 }
503}
504
514CommandCost CmdPlantTree(DoCommandFlags flags, TileIndex tile, TileIndex start_tile, uint8_t tree_to_plant, bool diagonal)
515{
518
519 if (start_tile >= Map::Size()) return CMD_ERROR;
520 /* Check the tree type within the current climate */
521 if (tree_to_plant != TREE_INVALID && !IsInsideBS(tree_to_plant, _tree_base_by_landscape[to_underlying(_settings_game.game_creation.landscape)], _tree_count_by_landscape[to_underlying(_settings_game.game_creation.landscape)])) return CMD_ERROR;
522
523 Company *c = (_game_mode != GM_EDITOR) ? Company::GetIfValid(_current_company) : nullptr;
524 int limit = (c == nullptr ? INT32_MAX : GB(c->tree_limit, 16, 16));
525
526 std::unique_ptr<TileIterator> iter = TileIterator::Create(tile, start_tile, diagonal);
527 for (; *iter != INVALID_TILE; ++(*iter)) {
528 TileIndex current_tile = *iter;
529 switch (GetTileType(current_tile)) {
530 case TileType::Trees:
531 /* no more space for trees? */
532 if (GetTreeCount(current_tile) == 4) {
533 msg = STR_ERROR_TREE_ALREADY_HERE;
534 continue;
535 }
536
537 /* Test tree limit. */
538 if (--limit < 1) {
539 msg = STR_ERROR_TREE_PLANT_LIMIT_REACHED;
540 break;
541 }
542
543 if (flags.Test(DoCommandFlag::Execute)) {
544 AddTreeCount(current_tile, 1);
545 MarkTileDirtyByTile(current_tile);
546 if (c != nullptr) c->tree_limit -= 1 << 16;
547 }
548 /* 2x as expensive to add more trees to an existing tile */
549 cost.AddCost(_price[Price::BuildTrees] * 2);
550 break;
551
552 case TileType::Water:
553 if (!IsCoast(current_tile) || IsSlopeWithOneCornerRaised(GetTileSlope(current_tile))) {
554 msg = STR_ERROR_CAN_T_BUILD_ON_WATER;
555 continue;
556 }
557 [[fallthrough]];
558
559 case TileType::Clear: {
560 if (IsBridgeAbove(current_tile)) {
561 msg = STR_ERROR_SITE_UNSUITABLE;
562 continue;
563 }
564
565 TreeType treetype = (TreeType)tree_to_plant;
566 /* Be a bit picky about which trees go where. */
567 if (_settings_game.game_creation.landscape == LandscapeType::Tropic && treetype != TREE_INVALID && (
568 /* No cacti outside the desert */
569 (treetype == TREE_CACTUS && GetTropicZone(current_tile) != TROPICZONE_DESERT) ||
570 /* No rainforest trees outside the rainforest, except in the editor mode where it makes those tiles rainforest tile */
571 (IsInsideMM(treetype, TREE_RAINFOREST, TREE_CACTUS) && GetTropicZone(current_tile) != TROPICZONE_RAINFOREST && _game_mode != GM_EDITOR) ||
572 /* And no subtropical trees in the desert/rainforest */
573 (IsInsideMM(treetype, TREE_SUB_TROPICAL, TREE_TOYLAND) && GetTropicZone(current_tile) != TROPICZONE_NORMAL))) {
574 msg = STR_ERROR_TREE_WRONG_TERRAIN_FOR_TREE_TYPE;
575 continue;
576 }
577
578 /* Test tree limit. */
579 if (--limit < 1) {
580 msg = STR_ERROR_TREE_PLANT_LIMIT_REACHED;
581 break;
582 }
583
584 if (IsTileType(current_tile, TileType::Clear)) {
585 /* Remove fields or rocks. Note that the ground will get barrened */
586 switch (GetClearGround(current_tile)) {
588 case ClearGround::Rocks: {
589 CommandCost ret = Command<Commands::LandscapeClear>::Do(flags, current_tile);
590 if (ret.Failed()) return ret;
591 cost.AddCost(ret.GetCost());
592 break;
593 }
594
595 default: break;
596 }
597 }
598
599 if (_game_mode != GM_EDITOR && Company::IsValidID(_current_company)) {
600 Town *t = ClosestTownFromTile(current_tile, _settings_game.economy.dist_local_authority);
601 if (t != nullptr) ChangeTownRating(t, RATING_TREE_UP_STEP, RATING_TREE_MAXIMUM, flags);
602 }
603
604 if (flags.Test(DoCommandFlag::Execute)) {
605 if (treetype == TREE_INVALID) {
606 treetype = GetRandomTreeType(current_tile, GB(Random(), 24, 8));
607 if (treetype == TREE_INVALID) treetype = TREE_CACTUS;
608 }
609
610 /* Plant full grown trees in scenario editor */
611 PlantTreesOnTile(current_tile, treetype, 0, _game_mode == GM_EDITOR ? TreeGrowthStage::Grown : TreeGrowthStage::Growing1);
612 MarkTileDirtyByTile(current_tile);
613 if (c != nullptr) c->tree_limit -= 1 << 16;
614
615 /* When planting rainforest-trees, set tropiczone to rainforest in editor. */
616 if (_game_mode == GM_EDITOR && IsInsideMM(treetype, TREE_RAINFOREST, TREE_CACTUS)) {
618 }
619 }
620 cost.AddCost(_price[Price::BuildTrees]);
621 break;
622 }
623
624 default:
625 msg = STR_ERROR_SITE_UNSUITABLE;
626 break;
627 }
628
629 /* Tree limit used up? No need to check more. */
630 if (limit < 0) break;
631 }
632
633 if (cost.GetCost() == 0) {
634 return CommandCost(msg);
635 } else {
636 return cost;
637 }
638}
639
641 int8_t x, y;
642};
643
644static void DrawTile_Trees(TileInfo *ti)
645{
646 switch (GetTreeGround(ti->tile)) {
647 case TreeGround::Shore: DrawShoreTile(ti->tileh); break;
648 case TreeGround::Grass: DrawClearLandTile(ti, GetTreeDensity(ti->tile)); break;
649 case TreeGround::Rough: DrawHillyLandTile(ti); break;
650 default: DrawGroundSprite(_clear_land_sprites_snow_desert[GetTreeDensity(ti->tile)] + SlopeToSpriteOffset(ti->tileh), PAL_NONE); break;
651 }
652
653 /* Do not draw trees when the invisible trees setting is set */
654 if (IsInvisibilitySet(TO_TREES)) return;
655
656 uint tmp = CountBits(ti->tile.base() + ti->x + ti->y);
657 uint index = GB(tmp, 0, 2) + (GetTreeType(ti->tile) << 2);
658
659 /* different tree styles above one of the grounds */
661 GetTreeDensity(ti->tile) >= 2 &&
662 IsInsideMM(index, TREE_SUB_ARCTIC << 2, TREE_RAINFOREST << 2)) {
663 index += 164 - (TREE_SUB_ARCTIC << 2);
664 }
665
666 assert(index < lengthof(_tree_layout_sprite));
667
668 const PalSpriteID *s = _tree_layout_sprite[index];
669 const TreePos *d = _tree_layout_xy[GB(tmp, 2, 2)];
670
671 /* combine trees into one sprite object */
673
674 TreeListEnt te[4];
675
676 /* put the trees to draw in a list */
677 uint trees = GetTreeCount(ti->tile);
678
679 for (uint i = 0; i < trees; i++) {
680 SpriteID sprite = s[0].sprite + (i == trees - 1 ? to_underlying(GetTreeGrowth(ti->tile)) : 3);
681 PaletteID pal = s[0].pal;
682
683 te[i].sprite = sprite;
684 te[i].pal = pal;
685 te[i].x = d->x;
686 te[i].y = d->y;
687 s++;
688 d++;
689 }
690
691 /* draw them in a sorted way */
692 int z = ti->z + GetSlopeMaxPixelZ(ti->tileh) / 2;
693
694 for (; trees > 0; trees--) {
695 uint min = te[0].x + te[0].y;
696 uint mi = 0;
697
698 for (uint i = 1; i < trees; i++) {
699 if ((uint)(te[i].x + te[i].y) < min) {
700 min = te[i].x + te[i].y;
701 mi = i;
702 }
703 }
704
705 SpriteBounds bounds{{}, {TILE_SIZE, TILE_SIZE, 48}, {te[mi].x, te[mi].y, 0}};
706 AddSortableSpriteToDraw(te[mi].sprite, te[mi].pal, ti->x, ti->y, z, bounds, IsTransparencySet(TO_TREES));
707
708 /* replace the removed one with the last one */
709 te[mi] = te[trees - 1];
710 }
711
713}
714
715
716static int GetSlopePixelZ_Trees(TileIndex tile, uint x, uint y, bool)
717{
718 auto [tileh, z] = GetTilePixelSlope(tile);
719
720 return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh);
721}
722
723static Foundation GetFoundation_Trees(TileIndex, Slope)
724{
725 return FOUNDATION_NONE;
726}
727
728static CommandCost ClearTile_Trees(TileIndex tile, DoCommandFlags flags)
729{
730 uint num;
731
733 Town *t = ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority);
734 if (t != nullptr) ChangeTownRating(t, RATING_TREE_DOWN_STEP, RATING_TREE_MINIMUM, flags);
735 }
736
737 num = GetTreeCount(tile);
738 if (IsInsideMM(GetTreeType(tile), TREE_RAINFOREST, TREE_CACTUS)) num *= 4;
739
740 if (flags.Test(DoCommandFlag::Execute)) DoClearSquare(tile);
741
743}
744
745static void GetTileDesc_Trees(TileIndex tile, TileDesc &td)
746{
747 TreeType tt = GetTreeType(tile);
748
750 td.str = STR_LAI_TREE_NAME_RAINFOREST;
751 } else {
752 td.str = tt == TREE_CACTUS ? STR_LAI_TREE_NAME_CACTUS_PLANTS : STR_LAI_TREE_NAME_TREES;
753 }
754
755 td.owner[0] = GetTileOwner(tile);
756}
757
758static void TileLoopTreesDesert(TileIndex tile)
759{
760 switch (GetTropicZone(tile)) {
765 }
766 break;
767
769 static const SoundFx forest_sounds[] = {
774 };
775 uint32_t r = Random();
776
777 if (Chance16I(1, 200, r) && _settings_client.sound.ambient) SndPlayTileFx(forest_sounds[GB(r, 16, 2)], tile);
778 break;
779 }
780
781 default: break;
782 }
783}
784
785static void TileLoopTreesAlps(TileIndex tile)
786{
787 int k = GetTileZ(tile) - GetSnowLine() + 1;
788
789 if (k < 0) {
790 switch (GetTreeGround(tile)) {
793 default: return;
794 }
795 } else {
796 uint density = std::min<uint>(k, 3);
797
800 SetTreeGroundDensity(tile, tg, density);
801 } else if (GetTreeDensity(tile) != density) {
802 SetTreeGroundDensity(tile, GetTreeGround(tile), density);
803 } else {
804 if (GetTreeDensity(tile) == 3) {
805 uint32_t r = Random();
806 if (Chance16I(1, 200, r) && _settings_client.sound.ambient) {
807 SndPlayTileFx((r & 0x80000000) ? SND_39_ARCTIC_SNOW_2 : SND_34_ARCTIC_SNOW_1, tile);
808 }
809 }
810 return;
811 }
812 }
814}
815
816/*
817 * Check if trees on this tile are allowed to spread.
818 * If they are allowed to spread, they are also allowed to die.
819 * @param tile The tile to check.
820 * @return Whether trees on this tile can spread.
821 */
822static bool TreesOnTileCanSpread(TileIndex tile)
823{
824 /* Desert and rainforest trees need special handling. */
825 if (_settings_game.game_creation.landscape == LandscapeType::Tropic) {
826 switch (GetTropicZone(tile)) {
828 /* Cacti never spread. */
829 return false;
831 return (_settings_game.construction.extra_tree_placement == ETP_SPREAD_ALL || _settings_game.construction.extra_tree_placement == ETP_SPREAD_RAINFOREST);
832 default:
833 return _settings_game.construction.extra_tree_placement == ETP_SPREAD_ALL;
834 }
835 }
836
837 return (_settings_game.construction.extra_tree_placement == ETP_SPREAD_ALL);
838}
839
840static void TileLoop_Trees(TileIndex tile)
841{
842 if (GetTreeGround(tile) == TreeGround::Shore) {
843 TileLoop_Water(tile);
844 } else {
845 switch (_settings_game.game_creation.landscape) {
846 case LandscapeType::Tropic: TileLoopTreesDesert(tile); break;
847 case LandscapeType::Arctic: TileLoopTreesAlps(tile); break;
848 default: break;
849 }
850 }
851
852 AmbientSoundEffect(tile);
853
854 /* TimerGameTick::counter is incremented by 256 between each call, so ignore lower 8 bits.
855 * Also, we use a simple hash to spread the updates evenly over the map.
856 * 11 and 9 are just some co-prime numbers for better spread.
857 */
858 uint32_t cycle = 11 * TileX(tile) + 9 * TileY(tile) + (TimerGameTick::counter >> 8);
859
860 /* Handle growth of grass (under trees/on TileType::Trees tiles) at every 8th processings, like it's done for grass on TileType::Clear tiles. */
861 if ((cycle & 7) == 7 && GetTreeGround(tile) == TreeGround::Grass) {
862 uint density = GetTreeDensity(tile);
863 if (density < 3) {
864 SetTreeGroundDensity(tile, TreeGround::Grass, density + 1);
866 }
867 }
868
869 if (_settings_game.construction.extra_tree_placement == ETP_NO_GROWTH_NO_SPREAD) return;
870
871 static const uint32_t TREE_UPDATE_FREQUENCY = 16; // How many tile updates happen for one tree update
872 if (cycle % TREE_UPDATE_FREQUENCY != TREE_UPDATE_FREQUENCY - 1) return;
873
874 switch (GetTreeGrowth(tile)) {
875 case TreeGrowthStage::Grown: // regular sized tree
876 if (_settings_game.game_creation.landscape == LandscapeType::Tropic &&
877 GetTreeType(tile) != TREE_CACTUS &&
879 AddTreeGrowth(tile, 1);
880 } else {
881 switch (GB(Random(), 0, 3)) {
882 case 0: // start destructing
883 AddTreeGrowth(tile, 1);
884 break;
885
886 case 1: // add a tree
887 if (GetTreeCount(tile) < 4 && TreesOnTileCanSpread(tile)) {
888 AddTreeCount(tile, 1);
890 break;
891 }
892 [[fallthrough]];
893
894 case 2: { // add a neighbouring tree
895 if (!TreesOnTileCanSpread(tile)) break;
896
897 TreeType treetype = GetTreeType(tile);
898
899 tile += TileOffsByDir(static_cast<Direction>(Random() % DIR_END));
900
901 if (!CanPlantTreesOnTile(tile, false)) return;
902
903 /* Don't plant trees, if ground was freshly cleared */
904 if (IsTileType(tile, TileType::Clear) && GetClearGround(tile) == ClearGround::Grass && !IsSnowTile(tile) && GetClearDensity(tile) != 3) return;
905
907
908 break;
909 }
910
911 default:
912 return;
913 }
914 }
915 break;
916
917 case TreeGrowthStage::Dead: // final stage of tree destruction
918 if (!TreesOnTileCanSpread(tile)) {
919 /* if trees can't spread just plant a new one to prevent deforestation */
921 } else if (GetTreeCount(tile) > 1) {
922 /* more than one tree, delete it */
923 AddTreeCount(tile, -1);
925 } else {
926 /* just one tree, change type into TileType::Clear */
927 switch (GetTreeGround(tile)) {
928 case TreeGround::Shore: MakeShore(tile); break;
930 case TreeGround::Rough: MakeClear(tile, ClearGround::Rough, 3); break;
932 uint density = GetTreeDensity(tile);
934 MakeSnow(tile, density);
935 break;
936 }
937 default: // snow or desert
938 if (_settings_game.game_creation.landscape == LandscapeType::Tropic) {
940 } else {
941 uint density = GetTreeDensity(tile);
943 MakeSnow(tile, density);
944 }
945 break;
946 }
947 }
948 break;
949
950 default:
951 AddTreeGrowth(tile, 1);
952 break;
953 }
954
956}
957
965{
966 /* Ensure _trees_tick_ctr can be decremented past zero only once for the largest map size. */
967 static_assert(2 * (MAX_MAP_SIZE_BITS - MIN_MAP_SIZE_BITS) - 4 <= std::numeric_limits<uint8_t>::digits);
968
969 /* byte underflow */
970 uint8_t old_trees_tick_ctr = _trees_tick_ctr;
972 return old_trees_tick_ctr <= _trees_tick_ctr;
973}
974
979static void PlantRandomTree(bool rainforest)
980{
981 uint32_t r = Random();
982 TileIndex tile = RandomTileSeed(r);
983
984 if (rainforest && GetTropicZone(tile) != TROPICZONE_RAINFOREST) return;
985 if (!CanPlantTreesOnTile(tile, false)) return;
986
987 TreeType tree = GetRandomTreeType(tile, GB(r, 24, 8));
988 if (tree == TREE_INVALID) return;
989
991}
992
993void OnTick_Trees()
994{
995 /* Don't spread trees if that's not allowed */
996 if (_settings_game.construction.extra_tree_placement == ETP_NO_SPREAD || _settings_game.construction.extra_tree_placement == ETP_NO_GROWTH_NO_SPREAD) return;
997
998 /* Skip some tree ticks for map sizes below 256 * 256. 64 * 64 is 16 times smaller, so
999 * this is the maximum number of ticks that are skipped. Number of ticks to skip is
1000 * inversely proportional to map size, so that is handled to create a mask. */
1001 int skip = Map::ScaleBySize(16);
1002 if (skip < 16 && (TimerGameTick::counter & (16 / skip - 1)) != 0) return;
1003
1004 /* place a tree at a random rainforest spot */
1005 if (_settings_game.game_creation.landscape == LandscapeType::Tropic) {
1006 for (uint c = Map::ScaleBySize(1); c > 0; c--) {
1007 PlantRandomTree(true);
1008 }
1009 }
1010
1011 if (!DecrementTreeCounter() || _settings_game.construction.extra_tree_placement == ETP_SPREAD_RAINFOREST) return;
1012
1013 /* place a tree at a random spot */
1014 PlantRandomTree(false);
1015}
1016
1017static TrackStatus GetTileTrackStatus_Trees(TileIndex, TransportType, uint, DiagDirection)
1018{
1019 return 0;
1020}
1021
1022static void ChangeTileOwner_Trees(TileIndex, Owner, Owner)
1023{
1024 /* not used */
1025}
1026
1027void InitializeTrees()
1028{
1029 _trees_tick_ctr = 0;
1030}
1031
1032static CommandCost TerraformTile_Trees(TileIndex tile, DoCommandFlags flags, int, Slope)
1033{
1034 return Command<Commands::LandscapeClear>::Do(flags, tile);
1035}
1036
1037
1038extern const TileTypeProcs _tile_type_trees_procs = {
1039 DrawTile_Trees, // draw_tile_proc
1040 GetSlopePixelZ_Trees, // get_slope_z_proc
1041 ClearTile_Trees, // clear_tile_proc
1042 nullptr, // add_accepted_cargo_proc
1043 GetTileDesc_Trees, // get_tile_desc_proc
1044 GetTileTrackStatus_Trees, // get_tile_track_status_proc
1045 nullptr, // click_tile_proc
1046 nullptr, // animate_tile_proc
1047 TileLoop_Trees, // tile_loop_proc
1048 ChangeTileOwner_Trees, // change_tile_owner_proc
1049 nullptr, // add_produced_cargo_proc
1050 nullptr, // vehicle_enter_tile_proc
1051 GetFoundation_Trees, // get_foundation_proc
1052 TerraformTile_Trees, // terraform_tile_proc
1053 nullptr, // check_build_above_proc
1054};
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr uint CountBits(T value)
Counts the number of set bits in a variable.
bool IsBridgeAbove(Tile t)
checks if a bridge is set above the ground of this tile
Definition bridge_map.h:45
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
Common return value for all commands.
void AddCost(const Money &cost)
Adds the given cost to the cost of the command.
Money GetCost() const
The costs as made up to this moment.
bool Failed() const
Did this command fail?
static std::unique_ptr< TileIterator > Create(TileIndex corner1, TileIndex corner2, bool diagonal)
Create either an OrthogonalTileIterator or DiagonalTileIterator given the diagonal parameter.
Definition tilearea.cpp:291
static TickCounter counter
Monotonic counter, in ticks, since start of game.
Functions related to clear (TileType::Clear) land.
Tables with sprites for clear land and fences.
Map accessors for 'clear' tiles.
bool IsClearGround(Tile t, ClearGround ct)
Set the type of clear tile.
Definition clear_map.h:64
void MakeSnow(Tile t, uint density=0)
Make a snow tile.
Definition clear_map.h:293
ClearGround
Ground types.
Definition clear_map.h:21
@ Desert
Desert with transition (1,3).
Definition clear_map.h:26
@ Rocks
Rocks with snow transition (0-3).
Definition clear_map.h:24
@ Fields
Farm fields (3).
Definition clear_map.h:25
@ Grass
Plain grass with dirt transition (0-3).
Definition clear_map.h:22
@ Rough
Rough mounds (3).
Definition clear_map.h:23
void MakeClear(Tile t, ClearGround g, uint density)
Make a clear tile.
Definition clear_map.h:252
ClearGround GetClearGround(Tile t)
Get the type of clear tile.
Definition clear_map.h:52
bool IsSnowTile(Tile t)
Test if a tile is covered with snow.
Definition clear_map.h:40
uint GetClearDensity(Tile t)
Get the density of a non-field clear tile.
Definition clear_map.h:76
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ Execute
execute the given command
Definition of stuff that is very close to a company, like the company struct itself.
CompanyID _current_company
Company currently doing an action.
Functions related to companies.
Direction
Defines the 8 directions on the map.
@ DIR_END
Used to iterate.
DiagDirection
Enumeration for diagonal directions.
@ EXPENSES_CONSTRUCTION
Construction costs.
@ EXPENSES_OTHER
Other expenses.
@ ClearTrees
Price for destroying trees.
@ BuildTrees
Price for planting trees.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
Definition enum_type.hpp:17
Functions related to world/map generation.
void IncreaseGeneratingWorldProgress(GenWorldProgress cls)
Increases the current stage of the world generation with one.
@ GWP_TREE
Generate trees.
Definition genworld.h:68
void SetGeneratingWorldProgress(GenWorldProgress cls, uint total)
Set the total of a stage of the world generation.
static constexpr uint MAP_HEIGHT_LIMIT_ORIGINAL
Original map height limit.
Definition genworld.h:50
All geometry types in OpenTTD.
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
uint8_t GetSnowLine()
Get the current snow line, either variable or static.
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
Mark a tile given by its index dirty for repaint.
uint GetPartialPixelZ(int x, int y, Slope corners)
Determines height at given coordinate of a slope.
Functions related to OTTD's landscape.
Command definitions related to landscape (slopes etc.).
@ Arctic
Landscape with snow levels.
@ Toyland
Landscape with funky industries and vehicles.
@ Tropic
Landscape with distinct rainforests and deserts,.
@ Temperate
Base landscape.
#define Point
Macro that prevents name conflicts between included headers.
uint DistanceSquare(TileIndex t0, TileIndex t1)
Gets the 'Square' distance between the two given tiles.
Definition map.cpp:175
TileIndex TileAddWrap(TileIndex tile, int addx, int addy)
This function checks if we add addx/addy to tile, if we do wrap around the edges.
Definition map.cpp:109
TileIndex RandomTileSeed(uint32_t r)
Get a random tile out of a given seed.
Definition map_func.h:643
static uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:427
static uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:417
#define RandomTile()
Get a valid random tile.
Definition map_func.h:654
TileIndexDiff TileOffsByDir(Direction dir)
Convert a Direction to a TileIndexDiff.
Definition map_func.h:586
static const uint MIN_MAP_SIZE_BITS
Minimal and maximal map width and height.
Definition map_type.h:37
static const uint MAX_MAP_SIZE_BITS
Maximal size of map is equal to 2 ^ MAX_MAP_SIZE_BITS.
Definition map_type.h:38
constexpr bool IsInsideBS(const T x, const size_t base, const size_t size)
Checks if a value is between a window started at some base point.
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition math_func.hpp:23
constexpr T Delta(const T a, const T b)
Returns the (absolute) difference between two (scalar) variables.
uint8_t _trees_tick_ctr
Determines when to consider building more trees.
Definition tree_cmd.cpp:45
Functions related to generic callbacks.
void AmbientSoundEffect(TileIndex tile)
Play an ambient sound effect for an empty tile.
Pseudo random number generator.
bool Chance16I(const uint32_t a, const uint32_t b, const uint32_t r)
Checks if a given randomize-number is below a given probability.
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
@ Original
The original algorithm.
@ None
No tree placer algorithm.
@ Improved
A 'improved' algorithm.
bool IsSlopeWithOneCornerRaised(Slope s)
Tests if a specific slope has exactly one corner raised.
Definition slope_func.h:88
uint SlopeToSpriteOffset(Slope s)
Returns the Sprite offset for a given Slope.
Definition slope_func.h:415
static constexpr int GetSlopeMaxPixelZ(Slope s)
Returns the height of the highest corner of a slope relative to TileZ (= minimal height).
Definition slope_func.h:173
Slope
Enumeration for the slope-type.
Definition slope_type.h:47
Foundation
Enumeration for Foundations.
Definition slope_type.h:92
@ FOUNDATION_NONE
The tile has no foundation, the slope remains unchanged.
Definition slope_type.h:93
Functions related to sound.
SoundFx
Sound effects from baseset.
Definition sound_type.h:46
@ SND_39_ARCTIC_SNOW_2
57 == 0x39 Tree ambient: arctic snow (2): heavy wind
Definition sound_type.h:105
@ SND_44_RAINFOREST_3
68 == 0x44 Tree ambient: rainforest ambient (3): monkeys
Definition sound_type.h:116
@ SND_34_ARCTIC_SNOW_1
52 == 0x34 Tree ambient: arctic snow (1): wind
Definition sound_type.h:100
@ SND_43_RAINFOREST_2
67 == 0x43 Tree ambient: rainforest ambient (2): lion
Definition sound_type.h:115
@ SND_42_RAINFOREST_1
66 == 0x42 Tree ambient: rainforest ambient (1): bird (1)
Definition sound_type.h:114
@ SND_48_RAINFOREST_4
72 == 0x48 Tree ambient: rainforest ambient (4): bird (2)
Definition sound_type.h:120
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:271
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames).
uint32_t tree_limit
Amount of trees we can (still) plant (times 65536).
T y
Y coordinate.
T x
X coordinate.
T x
X coordinate.
T y
Y coordinate.
T z
Z coordinate.
static uint ScaleBySize(uint n)
Scales the given value by the map size, where the given value is for a 256 by 256 map.
Definition map_func.h:330
static uint Size()
Get the size of the map.
Definition map_func.h:280
Combination of a palette sprite and a 'real' sprite.
Definition gfx_type.h:22
SpriteID sprite
The 'real' sprite.
Definition gfx_type.h:23
PaletteID pal
The palette (use PAL_NONE) if not needed).
Definition gfx_type.h:24
static Company * GetIfValid(auto index)
Tile description for the 'land area information' tool.
Definition tile_cmd.h:38
StringID str
Description of the tile.
Definition tile_cmd.h:39
std::array< Owner, 4 > owner
Name of the owner(s).
Definition tile_cmd.h:41
Tile information, used while rendering the tile.
Definition tile_cmd.h:32
Slope tileh
Slope of the tile.
Definition tile_cmd.h:33
TileIndex tile
Tile index.
Definition tile_cmd.h:34
Set of callback functions for performing tile operations of a given tile type.
Definition tile_cmd.h:154
Town data structure.
Definition town.h:63
int GetTileZ(TileIndex tile)
Get bottom height of the tile.
Definition tile_map.cpp:115
static bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition tile_map.h:178
std::tuple< Slope, int > GetTilePixelSlope(TileIndex tile)
Return the slope of a given tile.
Definition tile_map.h:289
TropicZone GetTropicZone(Tile tile)
Get the tropic zone.
Definition tile_map.h:238
Slope GetTileSlope(TileIndex tile)
Return the slope of a given tile inside the map.
Definition tile_map.h:279
void SetTropicZone(Tile tile, TropicZone type)
Set the tropic zone.
Definition tile_map.h:225
static TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition tile_map.h:96
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
@ TROPICZONE_RAINFOREST
Rainforest tile.
Definition tile_type.h:84
@ TROPICZONE_DESERT
Tile is desert.
Definition tile_type.h:83
@ TROPICZONE_NORMAL
Normal tropiczone.
Definition tile_type.h:82
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:100
static constexpr uint TILE_SIZE
Tile size in world coordinates.
Definition tile_type.h:15
@ Water
Water tile.
Definition tile_type.h:55
@ Void
Invisible tiles at the SW and SE border.
Definition tile_type.h:56
@ Trees
Tile with one or more trees.
Definition tile_type.h:53
@ Clear
A tile without any structures, i.e. grass, rocks, farm fields etc.
Definition tile_type.h:49
OrthogonalTileArea TileArea
Shorthand for the much more common orthogonal tile area.
Definition of the tick-based game-timer.
Base of the town class.
void ChangeTownRating(Town *t, int add, int max, DoCommandFlags flags)
Changes town rating of the current company.
Town * ClosestTownFromTile(TileIndex tile, uint threshold)
Return the town closest (in distance or ownership) to a given tile, within a given threshold.
bool IsTransparencySet(TransparencyOption to)
Check if the transparency option bit is set and if we aren't in the game menu (there's never transpar...
bool IsInvisibilitySet(TransparencyOption to)
Check if the invisibility option bit is set and if we aren't in the game menu (there's never transpar...
@ TO_TREES
trees
TransportType
Available types of transport.
void PlaceTree(TileIndex tile, uint32_t r, bool keep_density)
Make a random tree tile of the given tile.
Definition tree_cmd.cpp:171
uint PlaceTreeGroupAroundTile(TileIndex tile, TreeType treetype, uint radius, uint count, bool set_zone)
Place some trees in a radius around a tile.
Definition tree_cmd.cpp:432
static void PlantTreesOnTile(TileIndex tile, TreeType treetype, uint count, TreeGrowthStage growth)
Creates a tree tile Ground type and density is preserved.
Definition tree_cmd.cpp:98
static TreeType GetRandomTreeType(TileIndex tile, uint seed)
Get a random TreeType for the given tile based on a given seed.
Definition tree_cmd.cpp:140
static bool IsPointInTriangle(int x, int y, const Point &v1, const Point &v2, const Point &v3)
Returns true if the given coordinates lie within a triangle.
Definition tree_cmd.cpp:262
void GenerateTrees()
Place new trees.
Definition tree_cmd.cpp:479
static void CreateStarShapedPolygon(int radius, std::span< const BlobHarmonic > harmonics, std::span< Point > shape)
Creates a star-shaped polygon originating from (0, 0) as defined by the given harmonics.
Definition tree_cmd.cpp:203
static const uint16_t EDITOR_TREE_DIV
Game editor tree generation divisor factor.
Definition tree_cmd.cpp:49
static bool CanPlantTreesOnTile(TileIndex tile, bool allow_desert)
Tests if a tile can be converted to TileType::Trees This is true for clear ground without farms or ro...
Definition tree_cmd.cpp:59
void PlaceTreesRandomly()
Place some trees randomly.
Definition tree_cmd.cpp:369
static const uint16_t DEFAULT_TREE_STEPS
Default number of attempts for placing trees.
Definition tree_cmd.cpp:47
static const uint16_t DEFAULT_RAINFOREST_TREE_STEPS
Default number of attempts for placing extra trees at rainforest in tropic.
Definition tree_cmd.cpp:48
static bool IsPointInStarShapedPolygon(int x, int y, std::span< Point > shape)
Returns true if the given coordinates lie within a star shaped polygon.
Definition tree_cmd.cpp:281
static TreeGround TreeGroundFromClearGround(ClearGround clearground)
Get equivalent TreeGround for a ClearGround.
Definition tree_cmd.cpp:78
static void PlantRandomTree(bool rainforest)
Place a random tree on a random tile.
Definition tree_cmd.cpp:979
CommandCost CmdPlantTree(DoCommandFlags flags, TileIndex tile, TileIndex start_tile, uint8_t tree_to_plant, bool diagonal)
Plant a tree.
Definition tree_cmd.cpp:514
static void PlaceTreeAtSameHeight(TileIndex tile, int height)
Place a tree at the same height as an existing tree.
Definition tree_cmd.cpp:340
static void CreateRandomStarShapedPolygon(int radius, std::span< Point > shape)
Creates a random star-shaped polygon originating from (0, 0).
Definition tree_cmd.cpp:234
static void PlaceTreeGroups(uint num_groups)
Creates a number of tree groups.
Definition tree_cmd.cpp:300
ExtraTreePlacement
Where to place trees while in-game?
Definition tree_cmd.cpp:37
@ ETP_SPREAD_RAINFOREST
Grow trees on tiles that have them, only spread to new ones in rainforests.
Definition tree_cmd.cpp:39
@ ETP_NO_SPREAD
Grow trees on tiles that have them but don't spread to new ones.
Definition tree_cmd.cpp:38
@ ETP_NO_GROWTH_NO_SPREAD
Don't grow trees and don't spread them at all.
Definition tree_cmd.cpp:41
@ ETP_SPREAD_ALL
Grow trees and spread them without restrictions.
Definition tree_cmd.cpp:40
bool DecrementTreeCounter()
Decrement the tree tick counter.
Definition tree_cmd.cpp:964
Command definitions related to tree tiles.
Sprites to use and how to display them for tree tiles.
Map accessors for tree tiles.
static const uint TREE_COUNT_RAINFOREST
number of tree types for the 'rainforest part' of a sub-tropic map.
Definition tree_map.h:43
uint GetTreeCount(Tile t)
Returns the number of trees on a tile.
Definition tree_map.h:163
TreeGrowthStage GetTreeGrowth(Tile t)
Returns the tree growth stage.
Definition tree_map.h:195
static const uint TREE_COUNT_SUB_TROPICAL
number of tree types for the 'sub-tropic part' of a sub-tropic map.
Definition tree_map.h:44
static const uint TREE_COUNT_TOYLAND
number of tree types on a toyland map.
Definition tree_map.h:45
void MakeTree(Tile t, TreeType type, uint count, TreeGrowthStage growth, TreeGround ground, uint density)
Make a tree-tile.
Definition tree_map.h:244
void SetTreeGrowth(Tile t, TreeGrowthStage g)
Sets the tree growth stage of a tile.
Definition tree_map.h:226
TreeGround GetTreeGround(Tile t)
Returns the groundtype for tree tiles.
Definition tree_map.h:102
TreeType
List of tree types along all landscape types.
Definition tree_map.h:25
@ TREE_RAINFOREST
tree on the 'green part' on a sub-tropical map
Definition tree_map.h:28
@ TREE_TOYLAND
tree on a toyland map
Definition tree_map.h:31
@ TREE_SUB_ARCTIC
tree on a sub_arctic landscape
Definition tree_map.h:27
@ TREE_SUB_TROPICAL
tree on a sub-tropical map, non-rainforest, non-desert
Definition tree_map.h:30
@ TREE_TEMPERATE
temperate tree
Definition tree_map.h:26
@ TREE_CACTUS
a cactus for the 'desert part' on a sub-tropical map
Definition tree_map.h:29
@ TREE_INVALID
An invalid tree.
Definition tree_map.h:32
void AddTreeCount(Tile t, int c)
Add a amount to the tree-count value of a tile with trees.
Definition tree_map.h:180
TreeGround
Enumeration for ground types of tiles with trees.
Definition tree_map.h:52
@ SnowOrDesert
Snow or desert, depending on landscape.
Definition tree_map.h:55
@ Shore
Shore.
Definition tree_map.h:56
@ RoughSnow
A snow tile that is rough underneath.
Definition tree_map.h:57
@ Grass
Normal grass.
Definition tree_map.h:53
@ Rough
Rough land.
Definition tree_map.h:54
static const uint TREE_COUNT_SUB_ARCTIC
number of tree types on a sub arctic map.
Definition tree_map.h:42
TreeType GetTreeType(Tile t)
Returns the treetype of a tile.
Definition tree_map.h:87
void SetTreeGroundDensity(Tile t, TreeGround g, uint d)
Set the density and ground type of a tile with trees.
Definition tree_map.h:144
void AddTreeGrowth(Tile t, int a)
Add a value to the tree growth stage.
Definition tree_map.h:210
uint GetTreeDensity(Tile t)
Returns the 'density' of a tile with trees.
Definition tree_map.h:127
TreeGrowthStage
Enumeration for tree growth stages.
Definition tree_map.h:65
@ Grown
Fully grown tree.
Definition tree_map.h:69
@ Dead
Dead tree.
Definition tree_map.h:72
@ Growing1
First stage of growth.
Definition tree_map.h:66
static const uint TREE_COUNT_TEMPERATE
number of tree types on a temperate map.
Definition tree_map.h:41
void StartSpriteCombine()
Starts a block of sprites, which are "combined" into a single bounding box.
Definition viewport.cpp:759
void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int z, const SpriteBounds &bounds, bool transparent, const SubSprite *sub)
Draw a (transparent) sprite at given coordinates with a given bounding box.
Definition viewport.cpp:658
void EndSpriteCombine()
Terminates a block of sprites started by StartSpriteCombine.
Definition viewport.cpp:769
void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub, int extra_offs_x, int extra_offs_y)
Draws a ground sprite for the current tile.
Definition viewport.cpp:579
Functions related to (drawing on) viewports.
Functions related to water management.
void TileLoop_Water(TileIndex tile)
Let a water tile floods its diagonal adjoining tiles called from tunnelbridge_cmd,...
void ClearNeighbourNonFloodingStates(TileIndex tile)
Clear non-flooding state of the tiles around a tile.
Definition water_cmd.cpp:98
void MakeShore(Tile t)
Helper function to make a coast tile.
Definition water_map.h:383
bool IsCoast(Tile t)
Is it a coast tile?
Definition water_map.h:203